<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>멍개의 연구소</title>
    <link>https://meongae.tistory.com/</link>
    <description>개발을 좋아하는 멍청한 개구리의 연구소입니다.

굿즈판매: https://www.oround.com/mung</description>
    <language>ko</language>
    <pubDate>Mon, 29 Jun 2026 14:30:17 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>멍개.</managingEditor>
    <image>
      <title>멍개의 연구소</title>
      <url>https://tistory1.daumcdn.net/tistory/2746158/attach/9508765121d747caa7726cc63659f796</url>
      <link>https://meongae.tistory.com</link>
    </image>
    <item>
      <title>[ethereum] foundry를 이용하여 스마트 컨트랙트 개발하기</title>
      <link>https://meongae.tistory.com/103</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;안녕하세요 멍개입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-965de9f9-b960-467b-8705-2361b8302d6b&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-05080db0-0ea4-4fca-a23b-2dc08e27fdc9&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번글에서는 foundry을 이용하여 스마트 컨트랙트를 개발하는 방법을 다룹니다. foundry는 truffle, hardhat 처럼 스마트 컨트랙트 개발을 도와주는 도구입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5815c1c6-e0de-404f-a5c2-4fc3debe2985&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d9da6682-9f65-4832-9261-a0dd064b648a&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;foundry는 4개의 명령 도구를 제공합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9b66cbeb-3a59-4536-a956-b51e20425636&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #333333; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: inherit;&quot;&gt;&lt;span&gt;forge: &lt;/span&gt;&lt;span&gt;test, &lt;/span&gt;&lt;span&gt;compile, build, deploy&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot;&gt;&lt;span&gt;cast: rpc 통신&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot;&gt;&lt;span&gt;anvil: local testnet&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit;&quot;&gt;&lt;span&gt;chisel: REPL&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p id=&quot;SE-5d1507ca-c897-438c-bf83-dea715f9bd39&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b9e1567e-5453-4500-a051-898a0a496196&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;● 셋업&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-51d9422a-5813-4b6e-963d-1394f03f13a0&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;foundry는 공식문서를 통해 설치 가이드를 확인할 수 있습니다. foundry는 rust 기반이기 때문에 rust가 설치되어 있어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-740e93bc-c52a-4719-8ca9-42c537a23986&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://book.getfoundry.sh/getting-started/installation&quot;&gt;https://book.getfoundry.sh/getting-started/installation&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739781770625&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Foundry Book&quot; data-og-description=&quot;A book on all things Foundry&quot; data-og-host=&quot;book.getfoundry.sh&quot; data-og-source-url=&quot;https://book.getfoundry.sh/getting-started/installation&quot; data-og-url=&quot;https://book.getfoundry.sh/getting-started/installation&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://book.getfoundry.sh/getting-started/installation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://book.getfoundry.sh/getting-started/installation&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Foundry Book&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A book on all things Foundry&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;book.getfoundry.sh&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span&gt;foundry에서 스마트 컨트랙트 개발/테스트/배포하는 과정은 forge를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-370603d7-e291-4d62-8e56-e2294dd22690&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-101a2835-69f4-4e14-a39f-cc5ddcf548f8&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 프로젝트 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739781806758&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge init helloworld-contracts

Initializing /Users/jeongtaepark/Desktop/helloworld-contracts...
Installing forge-std in /Users/jeongtaepark/Desktop/helloworld-contracts/lib/forge-std (url: Some(&quot;https://github.com/foundry-rs/forge-std&quot;), tag: None)
'/Users/jeongtaepark/Desktop/helloworld-contracts/lib/forge-std'에 복제합니다...
remote: Enumerating objects: 1978, done.
remote: Counting objects: 100% (829/829), done.
remote: Compressing objects: 100% (191/191), done.
remote: Total 1978 (delta 762), reused 642 (delta 638), pack-reused 1149 (from 5)
오브젝트를 받는 중: 100% (1978/1978), 692.79 KiB | 13.86 MiB/s, 완료.
델타를 알아내는 중: 100% (1291/1291), 완료.
    Installed forge-std v1.9.5
    Initialized forge project&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1739781819629&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tree .

.
├── README.md
├── foundry.toml
├── lib
│   └── forge-std
│       ├── CONTRIBUTING.md
│       ├── LICENSE-APACHE
│       ├── LICENSE-MIT
│       ├── README.md
│       ├── foundry.toml
│       ├── package.json
│       ├── scripts
│       │   └── vm.py
│       ├── src
│       │   ├── Base.sol
│       │   ├── Script.sol
│       │   ├── StdAssertions.sol
│       │   ├── StdChains.sol
│       │   ├── StdCheats.sol
│       │   ├── StdError.sol
│       │   ├── StdInvariant.sol
│       │   ├── StdJson.sol
│       │   ├── StdMath.sol
│       │   ├── StdStorage.sol
│       │   ├── StdStyle.sol
│       │   ├── StdToml.sol
│       │   ├── StdUtils.sol
│       │   ├── Test.sol
│       │   ├── Vm.sol
│       │   ├── console.sol
│       │   ├── console2.sol
│       │   ├── interfaces
│       │   │   ├── IERC1155.sol
│       │   │   ├── IERC165.sol
│       │   │   ├── IERC20.sol
│       │   │   ├── IERC4626.sol
│       │   │   ├── IERC721.sol
│       │   │   └── IMulticall3.sol
│       │   ├── mocks
│       │   │   ├── MockERC20.sol
│       │   │   └── MockERC721.sol
│       │   └── safeconsole.sol
│       └── test
│           ├── StdAssertions.t.sol
│           ├── StdChains.t.sol
│           ├── StdCheats.t.sol
│           ├── StdError.t.sol
│           ├── StdJson.t.sol
│           ├── StdMath.t.sol
│           ├── StdStorage.t.sol
│           ├── StdStyle.t.sol
│           ├── StdToml.t.sol
│           ├── StdUtils.t.sol
│           ├── Vm.t.sol
│           ├── compilation
│           │   ├── CompilationScript.sol
│           │   ├── CompilationScriptBase.sol
│           │   ├── CompilationTest.sol
│           │   └── CompilationTestBase.sol
│           ├── fixtures
│           │   ├── broadcast.log.json
│           │   ├── test.json
│           │   └── test.toml
│           └── mocks
│               ├── MockERC20.t.sol
│               └── MockERC721.t.sol
├── script
│   └── Counter.s.sol
├── src
│   └── Counter.sol
└── test
    └── Counter.t.sol

13 directories, 58 files&lt;/code&gt;&lt;/pre&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;span&gt;&lt;b&gt;▶ foundry.toml&lt;/b&gt;: 프로젝트 정보를 가집니다. 해당 파일은 여러 옵션 정보를 가질 수 있으며, 깃허브에서 어떤 옵션 정보를 가질 수 있는지 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7f920fd1-9b4d-4064-8244-f7ebc931c1f5&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options&quot;&gt;https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739781832744&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;foundry/crates/config/README.md at master &amp;middot; foundry-rs/foundry&quot; data-og-description=&quot;Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. - foundry-rs/foundry&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options&quot; data-og-url=&quot;https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJpQ4p/hyYfCGxLzH/p2AQDUHDrfShKmp1udvgqk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/d9Zc7m/hyYfNBjSze/XWx7XHBWJSZG8q4LUznqR1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJpQ4p/hyYfCGxLzH/p2AQDUHDrfShKmp1udvgqk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/d9Zc7m/hyYfNBjSze/XWx7XHBWJSZG8q4LUznqR1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;foundry/crates/config/README.md at master &amp;middot; foundry-rs/foundry&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust. - foundry-rs/foundry&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;▶ lib&lt;/b&gt;: 깃허브로 다운받은 모듈을 의미합니다. 해당 모듈은 &lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;서브모듈(.gitmodules)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 형태로 관리됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d70d9c6a-0d28-409c-bbd0-8d7386f43a79&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;▶ scripts&lt;/b&gt;: forge script로 실행할 스크립트 코드를 관리합니다. 대표적으로 Deploy 관련 코드를 관리합니다. script 코드들은 solidity 기반으로 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fa80cf6e-2c06-4068-b86b-e478c8f0dd69&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;▶ test&lt;/b&gt;: 테스트 코드를 관리합니다. 테스트 코드는 solidity 기반으로 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6b2d9216-0034-4f12-bc45-0e6f516e306f&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;▶ src&lt;/b&gt;: 스마트 컨트랙트 소스코드를 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7c65d2cd-434a-4ba0-866b-5bdcde98977a&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-2032c8e2-68df-4e81-a15b-14521f747e47&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 의존성 - submodule 기반&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-571b477f-3f62-46ea-bf38-587747e5ff9d&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;forge의 install을 이용하면 submodule 형태로 외부 라이브러리를 손쉽게 추가할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739781844094&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge install transmissions11/solmate@v7

Installing solmate in /Users/jeongtaepark/Desktop/helloworld-contracts/lib/solmate (url: Some(&quot;https://github.com/transmissions11/solmate&quot;), tag: Some(&quot;v7&quot;))
'/Users/jeongtaepark/Desktop/helloworld-contracts/lib/solmate'에 복제합니다...
remote: Enumerating objects: 3085, done.
remote: Counting objects: 100% (177/177), done.
remote: Compressing objects: 100% (107/107), done.
remote: Total 3085 (delta 95), reused 120 (delta 69), pack-reused 2908 (from 1)
오브젝트를 받는 중: 100% (3085/3085), 832.96 KiB | 11.26 MiB/s, 완료.
델타를 알아내는 중: 100% (1973/1973), 완료.
'lib/ds-test' 경로에 대해 'lib/ds-test' (https://github.com/dapphub/ds-test) 하위 모듈 등록
'/Users/jeongtaepark/Desktop/helloworld-contracts/lib/solmate/lib/ds-test'에 복제합니다...
remote: Enumerating objects: 313, done.
remote: Counting objects: 100% (171/171), done.
remote: Compressing objects: 100% (79/79), done.
remote: Total 313 (delta 91), reused 132 (delta 83), pack-reused 142 (from 1)
오브젝트를 받는 중: 100% (313/313), 71.35 KiB | 17.84 MiB/s, 완료.
델타를 알아내는 중: 100% (130/130), 완료.
    Installed solmate v7&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-123ad6e9-7297-49c5-bcc7-e2db650110c7&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6456a408-3403-43b4-82d3-13feadc4f1b1&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이렇게 성공적으로 라이브러리가 추가되었다면 2가지 변경사항이 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1afd1dc5-f799-4dd8-8425-f663ed607814&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e105be88-9b55-43c7-bb14-e3bc0ee71cd1&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;lib/ 아래에 설치한 라이브러리가 추가됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f4a1ff31-2ea7-471f-9ba2-a1c423eec625&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;.gitmodules에 설치된 라이브러리의 정보가 추가됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-41ea9e57-db92-4b4b-8f04-c4a573521361&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7f332bac-fece-4a78-a01b-d30b1d5ba648&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;forge install을 이용할 때 중요한 점이 있습니다. forge install이 수행되면 설치 / 추가 완료후 commit을 생성하게 됩니다. 이떄 만약 .git에서 작업 공간에 변경사항이 있을경우 정상적으로 설치되지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3e791dce-aed4-49a4-9846-5f25dae574d6&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSb3iB/btsMlYg20Pz/LDPB8QwykAKE3EYjGer2R0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSb3iB/btsMlYg20Pz/LDPB8QwykAKE3EYjGer2R0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSb3iB/btsMlYg20Pz/LDPB8QwykAKE3EYjGer2R0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSb3iB%2FbtsMlYg20Pz%2FLDPB8QwykAKE3EYjGer2R0%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;773&quot; height=&quot;277&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-979aed78-8be5-4a47-9ed6-6d85fb8fa87f&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a3a3f03d-ae16-4d64-9b9c-e9d9a6fbefad&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 경우 두가지 해결법이 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0b16ffe1-5629-4191-88e2-5f8475e11160&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b1e69c3c-b47f-443c-8828-c5b900ab9076&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째는 현재 변경사항에 대한 커밋을 생성하여 작업 공간의 변경사항이 없는 상태에서 설치 진행하는 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9ce06652-aac9-4726-a0b1-53ef0a9e403f&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6ff01be5-c6cd-42c4-a4a5-265fd4003561&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 번째는 forge install할 때 커밋을 생성하지 않도록 하는 방법입니다. --no-commit 옵션을 이용하면 커밋을 생성하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1739781861796&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge install [패키지명] --no-commit&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 의존성 - Package Manager&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-5ad54866-50f7-477b-a0c8-82abd73575ee&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파이썬의 pypi, 노드의 npm과 같이 forge에서는 soldeer를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b7c580a9-6c02-4f81-9337-d00afd630274&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://soldeer.xyz/&quot;&gt;https://soldeer.xyz/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739781873790&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Soldeer - Solidity Package Manager&quot; data-og-description=&quot;Soldeer is a lightweight package manager for Solidity built in Rust.&quot; data-og-host=&quot;soldeer.xyz&quot; data-og-source-url=&quot;https://soldeer.xyz/&quot; data-og-url=&quot;https://soldeer.xyz&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://soldeer.xyz/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://soldeer.xyz/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Soldeer - Solidity Package Manager&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Soldeer is a lightweight package manager for Solidity built in Rust.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;soldeer.xyz&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1739781877058&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge soldeer install @openzeppelin-contracts~5.0.2

  Running soldeer install  

Dependency @openzeppelin-contracts-5.0.2.zip downloaded!
Writing @openzeppelin-contracts~5.0.2 to the lock file.
The dependency @openzeppelin-contracts-5.0.2 was unzipped!
Adding dependency @openzeppelin-contracts-5.0.2 to the config file
Added a new dependency to remappings @openzeppelin-contracts-5.0.2&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1739781883813&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tree . -L 2

.
├── README.md
├── dependencies
│   └── @openzeppelin-contracts-5.0.2
├── foundry.toml
├── lib
│   ├── forge-std
│   └── solmate
├── remappings.txt
├── script
│   └── Counter.s.sol
├── soldeer.lock
├── src
│   └── Counter.sol
└── test
    └── Counter.t.sol

8 directories, 7 files&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-e72a223d-c2b8-4773-bbaf-5a5126b77c23&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b876b791-86c5-4fcf-a99a-81a187a8df53&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;soldeer로 설치된 외부 라이브러리는 dependencies에 추가됩니다. 그리고 remappings.txt와 soldeer.lock이 추가됩니다.remappings.txt는 dependencies에 추가된 라이브러리 목록을 가지고 있는 파일이며 soldeer.lock은 소스코드 경로, 라이브러리 이름, 버전, 체크섬 정보를 가지고 있는 파일입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-80e944ce-99f4-405e-9f63-3e140517529c&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9aee7510-f014-431f-89ad-ca813e1d3312&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 깃허브 레포에서 forge로 구축된 프로젝트를 clone 했다면 soldeer로 관리중인 의존성 모듈을 설치해야 합니다. 이땐 update를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1739782046139&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge soldeer update 
  Running soldeer update  

Dependency @openzeppelin-contracts-5.0.2.zip downloaded!
The dependency @openzeppelin-contracts-5.0.2 was unzipped!
Writing @openzeppelin-contracts~5.0.2 to the lock file.&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-7dab37ee-432e-432e-bc96-d81ddd136e43&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-14eaddf7-b82d-471f-af6c-01e5b0f07bff&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&lt;b&gt;● 개발프로세스&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-20154150-3336-47b4-ab21-45441556ed4d&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;소스코드를 작성하고 컴파일 &amp;amp; 빌드를 하여 우리가 사용할 네트워크에 스마트 컨트랙트를 배포합니다. 그리고 이를 테스트는 개발 프로세스를 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1739781925889&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 소스코드 작성(with 테스트) 
2. 컴파일 &amp;amp; 빌드 
3. 배포 
4. 개별적으로 실행해보기 
5. 테스트 하기&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출금패턴이 적용된 컨트랙트를 기반으로 테스트 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-64ac6570-5fc8-4a4e-926b-182fd375c195&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://blog.naver.com/pjt3591oo/222594079769&quot;&gt;https://blog.naver.com/pjt3591oo/222594079769&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1739781944119&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[ethereum] solidity withdrawals pattern(출금패턴)&quot; data-og-description=&quot;안녕하세요 멍개입니다. https://meongae.tistory.com/82으로 이관되었습니다. 이번 포스트는 solidity에서...&quot; data-og-host=&quot;blog.naver.com&quot; data-og-source-url=&quot;https://blog.naver.com/pjt3591oo/222594079769&quot; data-og-url=&quot;https://blog.naver.com/pjt3591oo/222594079769&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bh80DL/hyYfWLO4lF/I15OplQJANMPreuuVFtol1/img.png?width=743&amp;amp;height=578&amp;amp;face=0_0_743_578&quot;&gt;&lt;a href=&quot;https://blog.naver.com/pjt3591oo/222594079769&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.naver.com/pjt3591oo/222594079769&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bh80DL/hyYfWLO4lF/I15OplQJANMPreuuVFtol1/img.png?width=743&amp;amp;height=578&amp;amp;face=0_0_743_578');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[ethereum] solidity withdrawals pattern(출금패턴)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 멍개입니다. https://meongae.tistory.com/82으로 이관되었습니다. 이번 포스트는 solidity에서...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 소스코드 작성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-40a911de-6b2a-4a1e-811b-6aab0ca80bd7&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;소스코드는 src/ 아래에서 관리합니다. forge 프로젝트 초기화 시 생성된 Counter.sol은 삭제합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d33d74cf-59f1-49e6-b0c8-df267a10174c&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 코드는 출금패턴이 적용된 코드입니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-75863e53-03ec-4aa7-872f-91480b34daaa&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;▶ src/WithdrawalContract.sol&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739781957202&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.24;

error AlreadyWithdrawal();

contract WithdrawalContract {
  address payable public richest;
  uint public mostAmount = 0;
  uint public totalAmount = 0;

  mapping (address =&amp;gt; uint) public pendingWithdrawals;

  receive() external payable {
    _receiveEther(msg.sender, msg.value);
  }

  constructor() payable {
    richest = payable(msg.sender);
    mostAmount = msg.value;
  }

  function becomeEther() public payable {
    _receiveEther(msg.sender, msg.value);
  }

  function _receiveEther(address sender, uint value) private {
    pendingWithdrawals[richest] += value;

    if (value &amp;gt; mostAmount) {
      richest = payable(sender);
      mostAmount = value;
    }

    totalAmount += value;
  }

  function withdraw() public {
    if (pendingWithdrawals[msg.sender] == 0) {
      revert AlreadyWithdrawal();
    }
    uint amount = pendingWithdrawals[msg.sender];
    // 리엔트란시(re-entrancy) 공격을 예방하기 위해
    // 송금하기 전에 보류중인 환불을 0으로 기억해 두십시오.
    pendingWithdrawals[msg.sender] = 0;
    payable(msg.sender).transfer(amount);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-6e2e8ad9-33d6-4ab1-8d75-a45d1f589ee1&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7fb8768a-293f-4e74-9d61-d9c298a9eec8&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-025f1a0f-1120-447c-8f55-c76dc8ff1abc&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 테스트 코드 작성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e830c1af-b665-4d37-b309-7506fb54bb77&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;forge 프로젝트 초기화 시 생성된 Counter.t.sol은 삭제합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6f2b1daa-0b31-4061-9bf4-7c8523702baa&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b07a2466-54c0-4049-8c6c-ed2ae4128273&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;테스트를 수행할 테스트 코드와 테스트 시 사용할 2개의 컨트랙트를 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-37d5774e-1f5e-42f3-a1f9-b56f24a55c3e&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;테슽 코드는 test/ 아래에서 관리되며 파일명은 &lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;*.t.sol&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 형태입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c4b8444e-7ea6-46cb-87f7-0a51ff4d8a95&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-192f4cd4-1ae5-460b-8376-5142f2f30053&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저, 출금 테스트시 사용할 2개의 컨트랙트를 만들어줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ae0bdea0-6f2f-413c-984c-5836114a95a6&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9f6573c9-6de0-43c8-a9a3-169594447eae&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;테스트 코드를 작성할 땐 forge-std/Test.sol, Console, Vm 등을 이용하게 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5b1d5d45-451b-4ab0-a623-9f5b8d73b8af&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;깃허브를 통해 어떤 기능을 사용할 수 있는지 알아볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8aba4641-6673-48d1-847f-01c1a4f3b945&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/foundry-rs/forge-std/tree/master/src&quot;&gt;https://github.com/foundry-rs/forge-std/tree/master/src&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1739781967883&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;forge-std/src at master &amp;middot; foundry-rs/forge-std&quot; data-og-description=&quot;Forge Standard Library is a collection of helpful contracts for use with forge and foundry. It leverages forge's cheatcodes to make writing tests easier and faster, while improving the UX of ch...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/foundry-rs/forge-std/tree/master/src&quot; data-og-url=&quot;https://github.com/foundry-rs/forge-std/tree/master/src&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GC1gu/hyYfH8UuaM/prAlzRvtTwhBNwg8HymTmk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bqTalg/hyYfTBzBb6/YOBCrjD5p6uHWU0q5zNOs1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/foundry-rs/forge-std/tree/master/src&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/foundry-rs/forge-std/tree/master/src&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GC1gu/hyYfH8UuaM/prAlzRvtTwhBNwg8HymTmk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bqTalg/hyYfTBzBb6/YOBCrjD5p6uHWU0q5zNOs1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;forge-std/src at master &amp;middot; foundry-rs/forge-std&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Forge Standard Library is a collection of helpful contracts for use with forge and foundry. It leverages forge's cheatcodes to make writing tests easier and faster, while improving the UX of ch...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;div&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;▶ ./test/NonPayableContract.sol&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739782068630&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.24;

import '../src/WithdrawalContract.sol';

contract NonPayableContract {
  // receive () external payable{}
  
  constructor () payable {}

  function send(WithdrawalContract _to, uint _amount) external {
    WithdrawalContract(_to).becomeEther{value: _amount}();
  }

  function withdraw(WithdrawalContract addr) public  {
    WithdrawalContract(addr).withdraw();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-0abcbd43-7d78-4f8b-b766-cd10eb09323a&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div style=&quot;background-color: #fdfdfd;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-08c95997-ccf3-42bf-90d1-391879d34d22&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-84379998-c264-461c-bb73-37510a6f9b98&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 컨트랙트는 생성시를 제외하고는 ETH를 전송받을 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-54f4e97d-168f-42d6-b4da-838d249942d7&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;constructor() payable{}가 존재하기 때문에 생성시 ETH를 받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1284e0bd-fd08-42cb-bd84-c27904e475dd&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;receive() payable{}가 없기 때문에 ETH를 전송받을 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f1aed804-4f85-4420-b9b3-22182a12a381&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-eed72968-7dd0-41dc-b278-55afdb007d02&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;▶ ./test/Payable.sol&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739782090038&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.24;

import '../src/WithdrawalContract.sol';

contract PayableContract {
  receive () external payable{}
  
  constructor () payable {}

  function send(WithdrawalContract _to, uint _amount) external {
    WithdrawalContract(_to).becomeEther{value: _amount}();
  }

  function withdraw(WithdrawalContract addr) public  {
    WithdrawalContract(addr).withdraw();
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8a5996c2-027d-4bab-9ab2-95c13a8f5ceb&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;SE-b7a2051c-8506-4a29-a699-e0550390b272&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5f1ce6b4-344e-4d10-b54d-d444dedaf2f5&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 컨트랙트는 언제든 ETH를 전송받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-113712ce-4e18-4e2e-8872-d62a1df01b9e&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;constructor() payable{}가 존재하기 때문에 생성시 ETH를 받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0cf93da1-8f21-457c-9ae5-4248908f2241&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;receive() payable{}가 있기 때문에 ETH를 전송받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cab23914-ba37-4285-8b2f-78ac916201f5&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-8ed468f3-0b7b-4d0f-bfd3-981d35ac7445&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;▶ ./test/WithdrawalContract.t.sol&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-bcc594c2-e117-4828-a50d-28d4c3f7f78f&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;test_*는 assertion을 수행하는 테스트 단위입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-46fe7e7f-04b8-46cc-8c40-4f6eb1e39aec&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;testFail_*은 exception이 발생하는지 테스트합니다. exception의 경우는 vm.expectRevert를 통해 어떤 exception이 발생했는지 검사할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dd159f71-99f3-4136-865c-8db09a3f4ae4&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-df61d13f-8ae4-4044-a125-71dfe36621f9&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;vm.expectRevert의 경우 testFail_*에서 수행될 경우 항상 pass가 되며, test_*로 작성된 테스트케이스에서 수행되어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-857abcc6-7659-42ee-8ab7-eb0de7f839e1&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-78159c36-3c05-4a0c-8546-7103db9eeb31&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;setUp은 test_*, testFail_*와 같이 테스트가 수행되기 전에 매번 호출됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782105492&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Test, console} from &quot;forge-std/Test.sol&quot;;
import {WithdrawalContract, AlreadyWithdrawal} from &quot;../src/WithdrawalContract.sol&quot;;

import {PayableContract} from &quot;./PayableContract.sol&quot;;
import {NonPayableContract} from &quot;./NonPayableContract.sol&quot;;

contract WithdrawalContractTest is Test {
    WithdrawalContract public withdrawalContract; // test target

    PayableContract public payableContract;
    NonPayableContract public nonPayableContract;
    
    function setUp() public pure {
      console.log(&quot;WithdrawalContractTest setUp&quot;);
    }

    function test_case0() public pure {
      console.log(&quot;WithdrawalContractTest test_case0&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d23e061e-a1a1-4ec2-94dd-72386e7f61f8&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fb2941af-e0bb-4ae7-86be-967419ac6dd4&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;forge test를 통해 테스트 코드를 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782122078&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge test -vvvv
[⠊] Compiling...
[⠢] Compiling 1 files with Solc 0.8.24
[⠆] Solc 0.8.24 finished in 2.09s
Compiler run successful!

Ran 1 test for test/WithdrawalContract.t.sol:WithdrawalContractTest
[PASS] test_case0() (gas: 3438)
Logs:
  WithdrawalContractTest setUp
  WithdrawalContractTest test_case0

Traces:
  [3438] WithdrawalContractTest::test_case0()
    ├─ [0] console::log(&quot;WithdrawalContractTest test_case0&quot;) [staticcall]
    │   └─ &amp;larr; [Stop]
    └─ &amp;larr; [Stop]

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.04ms (98.53&amp;micro;s CPU time)

Ran 1 test suite in 357.14ms (1.04ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e4608ae7-848e-4fbf-aba0-66afd8de9d8f&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-52e5bcf5-e616-440b-8502-64d380e52f16&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출력 결과를 깔끔하게 보고싶다면 -vvvv를 조정하면 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1d5da8d0-f3bf-4e0d-9c64-2a6c20a46959&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-vv&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-39838f75-6eb0-48bb-a42d-337acd25c629&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-vvv&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3de43310-44ae-4d30-8161-60892355ad41&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-vvvv&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6fd7f4a6-df52-48d8-85d2-b04ea65602eb&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;-vvvvv&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0d44daa2-a815-40fd-81ea-729c4a8eef00&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-772521e4-c7f0-460a-9f09-55fbbf0df64c&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;▶ setup&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-60d340cb-db3c-433e-be25-5a228cf4ba62&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 테스트를 수행하기 위해 setup에서 컨트랙트를 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782142538&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function setUp() public {
  withdrawalContract = new WithdrawalContract{value: 0}();
 
  payableContract = new PayableContract{value: 1000}();
  nonPayableContract = new NonPayableContract{value: 1000}();
  console.log('test contract balanceof: ', address(this).balance);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d30fb749-d533-4d7e-870d-65b83aebfeec&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #fdfdfd;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4cdbfc31-cfd7-4100-8e2e-bd00bdbded96&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1739782167478&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge test -vvvv
[⠒] Compiling...
[⠢] Compiling 1 files with Solc 0.8.24
[⠆] Solc 0.8.24 finished in 2.12s
Compiler run successful!

Ran 1 test for test/WithdrawalContract.t.sol:WithdrawalContractTest
[PASS] test_send() (gas: 188)
Logs:
  test contract balanceof:  79228162514264337593543948335

Traces:
  [188] WithdrawalContractTest::test_send()
    └─ &amp;larr; [Stop]

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.06ms (86.42&amp;micro;s CPU time)

Ran 1 test suite in 364.00ms (1.06ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;SE-cd3be7ff-ce82-4139-b299-e69fa5b27c95&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;▶ test_send&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-fe90cb2f-3426-47c0-892c-6fe5aac043c3&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;PayableContract와 NonPayableContract에서 send를 호출하여 WithdrawalContract로 ETH를 전송하는 테스트 코드를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div id=&quot;ssp-adcontent-2&quot;&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1739781986239&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; function test_send() public  {
      payableContract.send(withdrawalContract, 120);
      nonPayableContract.send(withdrawalContract, 100);

      assertEq(address(payableContract).balance, 880);
      assertEq(address(nonPayableContract).balance, 900);
      assertEq(address(withdrawalContract).balance, 220);    

      assertEq(withdrawalContract.mostAmount(), 120);
      assertEq(withdrawalContract.totalAmount(), 220);

      assertEq(withdrawalContract.pendingWithdrawals(address(payableContract)), 120);
      assertEq(withdrawalContract.pendingWithdrawals(address(nonPayableContract)), 100);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-deb606ac-3db0-4a69-91bf-de2c39169ce2&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-bb377b52-dddd-4145-9108-03fdc42496b6&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 만약 버그가 있다면 버그를 고쳐줍시다.(사실 WIthdrawalContract에 버그를 하나 심어 놨습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782185730&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;forge test -vvvv
[⠊] Compiling...
[⠆] Compiling 4 files with Solc 0.8.24
[⠰] Solc 0.8.24 finished in 2.22s
Compiler run successful!

Ran 1 test for test/WithdrawalContract.t.sol:WithdrawalContractTest
[FAIL. Reason: assertion failed: 100 != 120] test_send() (gas: 132991)
Logs:
  test contract balanceof:  79228162514264337593543948335

Traces:
  [418244] WithdrawalContractTest::setUp()
    ├─ [164308] &amp;rarr; new WithdrawalContract@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    │   └─ &amp;larr; [Return] 688 bytes of code
    ├─ [53281] &amp;rarr; new PayableContract@0x2e234DAe75C793f67A35089C9d99245E1C58470b
    │   └─ &amp;larr; [Return] 266 bytes of code
    ├─ [51275] &amp;rarr; new NonPayableContract@0xF62849F9A0B5Bf2913b396098F7c7019b51A820a
    │   └─ &amp;larr; [Return] 256 bytes of code
    ├─ [0] console::log(&quot;test contract balanceof: &quot;, 79228162514264337593543948335 [7.922e28]) [staticcall]
    │   └─ &amp;larr; [Stop]
    └─ &amp;larr; [Stop]

  [132991] WithdrawalContractTest::test_send()
    ├─ [81798] PayableContract::send(WithdrawalContract: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], 120)
    │   ├─ [71972] WithdrawalContract::becomeEther{value: 120}()
    │   │   └─ &amp;larr; [Stop]
    │   └─ &amp;larr; [Stop]
    ├─ [30335] NonPayableContract::send(WithdrawalContract: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], 100)
    │   ├─ [23009] WithdrawalContract::becomeEther{value: 100}()
    │   │   └─ &amp;larr; [Stop]
    │   └─ &amp;larr; [Stop]
    ├─ [0] VM::assertEq(880, 880) [staticcall]
    │   └─ &amp;larr; [Return]
    ├─ [0] VM::assertEq(900, 900) [staticcall]
    │   └─ &amp;larr; [Return]
    ├─ [0] VM::assertEq(220, 220) [staticcall]
    │   └─ &amp;larr; [Return]
    ├─ [383] WithdrawalContract::mostAmount() [staticcall]
    │   └─ &amp;larr; [Return] 120
    ├─ [0] VM::assertEq(120, 120) [staticcall]
    │   └─ &amp;larr; [Return]
    ├─ [295] WithdrawalContract::totalAmount() [staticcall]
    │   └─ &amp;larr; [Return] 220
    ├─ [0] VM::assertEq(220, 220) [staticcall]
    │   └─ &amp;larr; [Return]
    ├─ [550] WithdrawalContract::pendingWithdrawals(PayableContract: [0x2e234DAe75C793f67A35089C9d99245E1C58470b]) [staticcall]
    │   └─ &amp;larr; [Return] 100
    ├─ [0] VM::assertEq(100, 120) [staticcall]
    │   └─ &amp;larr; [Revert] assertion failed: 100 != 120
    └─ &amp;larr; [Revert] assertion failed: 100 != 120

Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 1.01ms (188.06&amp;micro;s CPU time)

Ran 1 test suite in 1.08s (1.01ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)

Failing tests:
Encountered 1 failing test in test/WithdrawalContract.t.sol:WithdrawalContractTest
[FAIL. Reason: assertion failed: 100 != 120] test_send() (gas: 132991)

Encountered a total of 1 failing tests, 0 tests succeeded&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a05b5307-24d7-4d50-a995-60a20e4e9d7b&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8a1cbffd-d5a8-436a-a8f5-b91528120eff&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;에러가 발생합니다. 그 이유는 _receiveEther에서 첫 번째 호출되는 코드에 문제가 있기 떄문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782199997&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pendingWithdrawals[richest] += value;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-29544f05-30ef-48dd-98dc-75d67438ac1a&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-973ee89e-d466-451f-b5ee-c6db24788fca&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 코드를 다음과 같이 수정합니다. richest가 아닌 호출한 주소의 자산을 변경해주어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-735af73b-bafe-4d37-9c9a-69f5cc504664&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1739782211046&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pendingWithdrawals[msg.sender] += value;&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-0f79775b-c8dd-4cdd-97b6-3069026ac40b&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 다시 테스트를 수행하면 테스트를 모두 통과합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8d426aae-9bd4-407e-bea8-b291247774ae&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-5664e072-8831-4b8f-8cfb-0654370c91db&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;▶ withdraw 호출&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-e569b872-e343-47d8-83ff-7ecd7b15db25&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;withdraw를 호출하는 경우에 따라 케이스를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-107beb60-cc35-49b2-9366-19b834113135&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9c7ad4e4-d520-4f92-b4e1-ef66ad8ef042&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;send 이후 withdraw하는 경우&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-87eb243a-1ff4-407b-9ebb-1923b4856a27&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;send를 하지 않고 withdraw하는 경우&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c41aff78-3302-4593-9a2b-d5d2c1c2e5b9&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;send 이후 여러번의 withdraw하는 경우&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782227582&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function test_withdrawByRichest() public {
  payableContract.send(withdrawalContract, 120);
  payableContract.withdraw(withdrawalContract);
}
function testFail_withdrawByNoSend() public {
  payableContract.withdraw(withdrawalContract);
}
function testFail_multiWithdraw() public {
  payableContract.send(withdrawalContract, 120);
  payableContract.withdraw(withdrawalContract);
  payableContract.withdraw(withdrawalContract);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-556ca18f-0c4c-4ae7-bbd9-9c8b67f6955f&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-01d505b3-9ece-442f-bdca-79f011943c36&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막으로 receive() external {}이 구현되지 않은 컨트랙트가 호출하는 경우를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782239882&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function testFail_withdrawByNonPayable() public {
  nonPayableContract.send(withdrawalContract, 100);
  nonPayableContract.withdraw(withdrawalContract);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-343d569f-5f88-47f2-a38d-d4d9c288f1cc&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b397b0d7-fce6-4a44-bb50-6dc0daa2ec1f&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 중요한 점은 실패를 검증할 경우 testFail을 이용한다는 점 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-327a2925-614d-43db-b84b-40a572e9760a&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-739e57bf-01f1-4000-8d96-f20945b3493c&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; mocking&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-ba8f2a90-9403-4485-ae47-c7d07950f5bf&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 외에도 forge의 경우 vm을 통해 여러 모킹을 수행할수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e89903d4-e085-4831-906c-e5678f2b49cf&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-b06090d4-ad4f-4124-a600-726672bcb3e8&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;▶ caller 변경&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739782248201&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vm.prank(address(0)); // msg.sender가 변경됨&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bfd6ac85-2104-49f4-8b10-f72b2392d821&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-2262cf9a-72e5-417e-af57-b82bf32d7474&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;▶ block.timestamp 변경&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739782259717&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vm.warp(1234); // 컨트랙트에서 block.timestamp를 호출할 때 값 변경&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f5e70047-bbee-43bf-a6a1-2d0ea3ad4fab&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-d573becc-1c8e-4a04-a8d8-c188f9bd6a91&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; Deploy&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-d90086f8-9a53-4363-97e5-d1a8364ec98d&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;테스트 코드와 함께 컨트랙트 코드를 완성했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e0a019e3-1b35-44f5-842d-f3c3804a199c&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-54157f38-7c78-4723-8bdf-414cea8b668f&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 우리는 forge를 이용하여 스마트 컨트랙트를 배포할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-118ca803-a005-4af3-9995-e9820e5ecf0b&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e412c378-d7be-4463-8434-491def6ab9cb&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트를 배포하기에 앞서서 anvil을 이용하여 가상의 블록체인 네트워크를 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782277957&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ anvil&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b4cc6c95-b5d2-4e14-a1d5-89a139f56f10&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #fdfdfd;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #000000; color: #000000; text-align: left;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9b6b5537-404e-47c6-a5ef-9ef8949f5310&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0848fd10-b053-4d91-974c-b43615f27907&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;forge create를 이용하면 src에 있는 특정 컨트랙트를 배포할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782293997&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge create ./src/WithdrawalContract.sol:WithdrawalContract \
  --rpc-url http://localhost:8545 \
  --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-72a081c3-de27-4a1f-b7b5-8cdfe0b09fbb&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3030f5d9-831a-4fcf-b36e-9c0138bb40c1&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음과 같이 실행 결과를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782313591&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[⠊] Compiling...
No files changed, compilation skipped
Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
Transaction hash: 0xdb6ecae0d35a247bc700222b02fa596ac8cb0f9748378f1a0975afcabe4ef028&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7dd7281f-749e-40b6-94a9-ce202414d809&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-19b6d8ba-332d-4c52-b2d6-286094bc4c9d&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 우리가 하나의 컨트랙트가 아닌 여러 컨트랙트를 배포해야 하는 상황이 올 수 있습니다. 이때는 forge script를 이용합니다. script 아래에 Counter.s.sol은 지워준 후 WithdrawalContract.s.sol을 만들어 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6f2f1fd6-5c16-4051-9a4a-c60774faf622&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-06977ec9-8d86-4b9a-bbaf-545dd8c0997c&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;▶ script/WithdrawalContract.s.sol&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739782325503&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from &quot;forge-std/Script.sol&quot;;
import {WithdrawalContract} from &quot;../src/WithdrawalContract.sol&quot;;

contract WithdrawalContractScript is Script {
    function setUp() public {}

    function run() public {
      vm.broadcast();
      WithdrawalContract withdrawalContract = new WithdrawalContract();

      console.log(&quot;create withdrawalContract contract address: &quot;, address(withdrawalContract));
      console.log(&quot;withdrawalContract richest: &quot;, withdrawalContract.richest());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7344c9f2-2cc7-45ea-9a4a-a60371efcfc9&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9654c26d-066d-40d9-aac5-52dd0de0388d&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;vm.startBroadcast&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는&lt;/span&gt;&lt;span&gt;&lt;b&gt; broadcast(배포)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 수행할 어카운트를 설정할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4e94d506-2d5c-4b5d-a38e-77dd08c26a2e&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;vm.envUint&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 환경변수를 읽어올 수 있으며 정의되어있지 않다면 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782337980&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/ SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from &quot;forge-std/Script.sol&quot;;
import {WithdrawalContract} from &quot;../src/WithdrawalContract.sol&quot;;

contract WithdrawalContractScript is Script {
    function setUp() public {}

    function run() public {
      vm.startBroadcast(
        // vm.envUint(&quot;PRIVATE_KEY&quot;) // env check: if not set, will throw error
      );
      WithdrawalContract withdrawalContract = new WithdrawalContract();

      console.log(&quot;create withdrawalContract contract address: &quot;, address(withdrawalContract));
      console.log(&quot;withdrawalContract richest: &quot;, withdrawalContract.richest());

      vm.stopBroadcast();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-42b8becc-099d-444f-9f8a-612539fee2a5&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;pre id=&quot;code_1739782351567&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ forge script ./script/WithdrawalContract.s.sol:WithdrawalContractScript \
  --rpc-url http://localhost:8545 \
  --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
  --broadcast&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-78c3b71e-fef8-4580-92b6-775581660379&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #fdfdfd;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0c3855b5-e6a9-405c-8fbb-33e255887096&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ab4531c5-970a-4449-9a92-db3ee4389ce3&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음과 같이 실행 결과와 출력 결과를 확인할 수 있습니다. 혹여나 Counter.s.sol을 삭제하였는데도 해당 파일을 찾을 수 없다고 할 경우 &lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;cache/&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 지우면 됩니다. 만약 --broadcast가 없다면 실제로 배포는 되지 않고 somulation만 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782367261&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[⠒] Compiling...
No files changed, compilation skipped
EIP-3855 is not supported in one or more of the RPCs used.
Unsupported Chain IDs: 31337.
Contracts deployed with a Solidity version equal or higher than 0.8.20 might not work properly.
For more information, please see https://eips.ethereum.org/EIPS/eip-3855
Script ran successfully.

== Logs ==
  create withdrawalContract contract address:  0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
  withdrawalContract richest:  0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266

## Setting up 1 EVM.

==========================

Chain 31337

Estimated gas price: 1.753776101 gwei

Estimated total gas used for script: 294476

Estimated amount required: 0.000516444971118076 ETH

==========================

##### anvil-hardhat
✅  [Success]Hash: 0xc245d6b750a0aaf7782d99a3d57282c9eda0cb085b132105551c66514fffbecf
Contract Address: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
Block: 2
Paid: 0.000198673018162866 ETH (226566 gas * 0.876888051 gwei)

✅ Sequence #1 on anvil-hardhat | Total Paid: 0.000198673018162866 ETH (226566 gas * avg 0.876888051 gwei)
                                                                                                                                                           

==========================

ONCHAIN EXECUTION COMPLETE &amp;amp; SUCCESSFUL.

Transactions saved to: /Users/jeongtaepark/Desktop/helloworld-contracts/broadcast/WithdrawalContract.s.sol/31337/run-latest.json

Sensitive values saved to: /Users/jeongtaepark/Desktop/helloworld-contracts/cache/WithdrawalContract.s.sol/31337/run-latest.json&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cbcd4b12-d501-4824-b268-b04641d62d4c&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-290f0b35-853f-4af2-ad90-e77840e41fed&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;middot; cast&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-6c4ef963-2849-46fe-bbe5-55292382ec36&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;cast는 배포된 컨트랙트를 테스트하기 위해 rpc 통신을 수행하는 도구입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a45b149e-1159-4632-952f-9d1f2586f2ef&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6243839a-d5ab-45ab-b2df-0c70be82115b&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;조회를 위한 call과 트랜잭션 발생을 위한 send 명령어를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782387049&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cast call \
  [컨트랙트 주소]  \
  &quot;richest()(address)&quot; \
  --rpc-url http://localhost:8545&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-455417e3-5e3c-4009-81fc-713ee6356d27&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #fdfdfd;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1739782396531&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a34b1d23-7a74-406a-a979-fe774d0d0705&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b3c7a940-f43a-42d1-b0d5-94de0658afc9&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 트랜잭션을 발생하고 싶다면 send를 이용합니다. 이때 value를 지정하면 이더를 전송할 수 있습니다&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782404016&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  function test(uint _amount) public {
    pendingWithdrawals[msg.sender] += _amount;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-00664287-4aa2-4035-a15f-bee96fc65d05&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1b7e8404-2f93-475d-98bc-9c4baf8da396&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 앞의 test 함수를 호출하기 위해서는 다음과 같이 send를 호출할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782416233&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cast send \
  [컨트랙트 주소] \
  --rpc-url http://localhost:8545 \
  --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
  &quot;test(uint)&quot; 1000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5e6356c7-75ff-49b3-8bdf-078b0b7df88c&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-47dd64c3-2a2c-4847-a53d-064d5f2d50f7&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;cast는 abi-encode를 통해 함수 호출시 포함되어야 할 input 데이터를 생성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782427425&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cast abi-encode &quot;test(uint)&quot; 1000
0x00000000000000000000000000000000000000000000000000000000000003e8&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-acd619cd-c3bf-408b-8b56-b6d16e7a841b&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-84af6394-4c7b-4381-8033-6c2e015fde7d&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;cast는 이 외에도 block, transaction등과 같은 여러 명령들을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-25473636-19f3-4f8d-9a28-41780ac4533b&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://book.getfoundry.sh/reference/cast/&quot;&gt;https://book.getfoundry.sh/reference/cast/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1739782436791&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Foundry Book&quot; data-og-description=&quot;A book on all things Foundry&quot; data-og-host=&quot;book.getfoundry.sh&quot; data-og-source-url=&quot;https://book.getfoundry.sh/reference/cast/&quot; data-og-url=&quot;https://book.getfoundry.sh/reference/cast/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://book.getfoundry.sh/reference/cast/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://book.getfoundry.sh/reference/cast/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Foundry Book&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A book on all things Foundry&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;book.getfoundry.sh&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-25829af5-6e4a-45a1-b03a-36f7cd247b14&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-9586b6d2-36bb-4893-9b57-40c2cb2c2dc1&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 코드 포맷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-0ba94731-a7db-4891-971c-44203729aa41&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;forge느 fmt를 이용하여 모든 코드의 포맷팅을 맞춰줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-53ed6c5f-3ca3-4a85-836c-48903228ca93&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-90384361-1e11-4af0-915e-018ce9fbf449&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;forge는 이 외에도 편의를 위한 여러 명령어를 제공하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-781452d9-781a-4e6e-892e-f0285e3f28fe&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;a href=&quot;https://book.getfoundry.sh/reference/forge/&quot;&gt;https://book.getfoundry.sh/reference/forge/&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cc43b6a7-b692-4f4d-bceb-1a8b9a2f1605&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #ffffff;&quot;&gt;&lt;a style=&quot;color: #000000; text-align: left;&quot; href=&quot;https://book.getfoundry.sh/reference/forge/&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;
&lt;div&gt;&lt;b&gt;Foundry Book&lt;/b&gt;
&lt;p style=&quot;color: #999999;&quot; data-ke-size=&quot;size16&quot;&gt;A book on all things Foundry&lt;/p&gt;
&lt;p style=&quot;color: #00a832;&quot; data-ke-size=&quot;size16&quot;&gt;book.getfoundry.sh&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6890ba2f-b701-45cf-acb7-9b1c83aeb1dd&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7a8e0f91-5716-4486-b9b6-9b04a06c8785&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-cf5b9977-9443-4403-960b-7948f3f7c248&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; anvil&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-460afe4e-2d1d-4e29-bc3e-a9b4a25afae5&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;anvil은 기본으로 설정된 mnemonic을 기반으로 로컬에 테스트 네트워크를 구축합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739782450436&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;test test test test test test test test test test test junk&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-abc19f01-014f-43e2-963a-d211d9f5cccf&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-dd1085ac-cdd0-485a-ad78-83e70c624e7d&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음과 같이 특정 네트워크를 포크하여 임의로 block 생성 주기를 변경하여 로컬 네트워크를 구축할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-48999655-b6d0-48f4-a15b-065990db0834&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ac5e3042-28ca-4002-8cae-9d510acb9a31&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이는 이미 다른 네트워크에 있는 특정 스마트 컨트랙트를 테스트할 때 사용하면 상당히 도움이 많이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3dcabba5-e92e-4ab7-a235-83e8d672af5f&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-27b4df70-903c-453a-9065-44cc53d61254&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;auto-impersonate 옵션은 임의로 블록을 생성하는 옵션이며 block-time은 블록 생성 주기입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9890f968-7ce2-4729-80f7-662e2d7347bd&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div style=&quot;background-color: #fdfdfd;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ef59dd56-0add-4761-ad63-21f6a6da7feb&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;625&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NQasm/btsMmshBOqO/RcsgHmN1i9g1dxqS10KXw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NQasm/btsMmshBOqO/RcsgHmN1i9g1dxqS10KXw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NQasm/btsMmshBOqO/RcsgHmN1i9g1dxqS10KXw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNQasm%2FbtsMmshBOqO%2FRcsgHmN1i9g1dxqS10KXw0%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;773&quot; height=&quot;625&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;625&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fc578482-c360-409f-a5a2-b3344a2be19c&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-041e837e-293e-42a5-b6c1-80df38d20208&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7883434f-5132-43d2-9483-b9db97dc5efa&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지 foundry에서 제공하는 forge, anvil, cast를 다뤄보았습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aa0faf52-b78e-4e56-a8ae-9b99457cd8f7&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #ffffff;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>블록체인</category>
      <category>Anvil</category>
      <category>cast</category>
      <category>evm</category>
      <category>forge</category>
      <category>Foundry</category>
      <category>smartcontract</category>
      <category>블록체인</category>
      <category>스마트</category>
      <category>스마트컨트랙트</category>
      <category>컨트랙트</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/103</guid>
      <comments>https://meongae.tistory.com/103#entry103comment</comments>
      <pubDate>Mon, 17 Feb 2025 17:57:20 +0900</pubDate>
    </item>
    <item>
      <title>[블록체인] multi-sig와 key rotation을 이용한 악용사례</title>
      <link>https://meongae.tistory.com/102</link>
      <description>&lt;div id=&quot;SE-91fa1e8a-e653-4bfa-af0e-70415f8c20d7&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-809b949d-d9e2-4cf1-b3cc-b62f31a2709c&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;안녕하세요 멍개입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-27fee266-0aa6-48e2-9a28-c3472b1099e7&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-61b282e1-91b1-4dab-85d8-5cf8c93cae17&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 시간엔 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;multi-sig&lt;/b&gt;&lt;/span&gt;&lt;span&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #ff9300;&quot;&gt;&lt;b&gt;key rotation&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 이용한 사기 수법을 소개합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-49a9d284-4230-4ebf-b13e-7fa54b16bef3&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1b43a0d8-09b5-4500-9ae9-5db62abe54e3&quot; style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;본 포스트의 목적은 사기 수법을 공개함으로써 피해자가 없기를 바라는 마음으로 작성합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-70f5f21f-5eca-469c-84a7-8d5db215be22&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;p id=&quot;SE-078e740b-df64-41bc-9771-8762420b5f83&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;evm, aptos, solana 등 대부분의 블록체인에서는 어카운트 구조를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egJlD9/btsMmfpgCt0/WGQxkC8qJReIEMFHgoVF41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egJlD9/btsMmfpgCt0/WGQxkC8qJReIEMFHgoVF41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egJlD9/btsMmfpgCt0/WGQxkC8qJReIEMFHgoVF41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FegJlD9%2FbtsMmfpgCt0%2FWGQxkC8qJReIEMFHgoVF41%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;296&quot; height=&quot;311&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div id=&quot;SE-f6afd125-fc64-4f47-b858-9cb65c8cebcf&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6a034317-b773-4c59-ab14-6a8fa8993de3&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개인키는 해당 어카운트의 모든 권한을 가지게 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2730ff47-aae3-4d2b-b4e1-197c847566ce&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f6fce884-a520-4c3c-8c38-30c930324156&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 다중서명(Multi-Sig) or 권한(Permission)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6ffd7c70-9d38-40aa-ad33-fe0868603a3f&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;한 어카운트를 하나의 개인키가 아닌 다수의 개인키를 등록시켜서 다수의 개인키 서명을 받아야 트랜잭션을 성공시키는 방법이 multi sig 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-79f598a3-913f-4a9a-8e48-3ee4f4c22ebb&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9a18bf72-73df-4633-aba1-a7eb10bd13ee&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;multi sig를 사용하는 이유는 어카운트의 제어권을 여러 개인키로 분산함으로써 도난 / 무단 액세스 등의 위험으로부터 보호하기 위함입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ceb22d65-b8bc-4387-814b-ffef73925f16&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2de29dff-8bf7-4153-8a90-6736d5fa19f7&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbZ1en/btsMma2D4A9/Cxl6KkbC9z9mqg6UcfQAd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbZ1en/btsMma2D4A9/Cxl6KkbC9z9mqg6UcfQAd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbZ1en/btsMma2D4A9/Cxl6KkbC9z9mqg6UcfQAd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbZ1en%2FbtsMma2D4A9%2FCxl6KkbC9z9mqg6UcfQAd0%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;536&quot; height=&quot;311&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9f2b3a20-6156-42a6-bd01-139659ecf252&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-63d49d80-221b-4851-8c45-91dc11b33380&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 되면 기존의 개인키로만 트랜잭션을 서명하더라도 해당 트랜잭션이 실행되지 않습니다. 추가적으로 등록된 개인키의 서명이 필요합니다. 이 부분은 블록체인 네트워크마다 다른 개념으로 등록이 가능할 수 있는데. aptos의 경우는 등록된 개인키마다 가중치를 부여하여 일정 이상의 가중치를 넘길만큼의 서명을 받으면 트랜잭션을 실행합니다. tron의 경우는 등록된 개인키마다 권한(permission)을 부여하여 개인키마다 권한을 부여할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-57638583-db44-4095-b2a2-e8b7b76a2065&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;583&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzUc8i/btsMkwMIGQv/ldfGDrWDBqEu8tmtc1dlP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzUc8i/btsMkwMIGQv/ldfGDrWDBqEu8tmtc1dlP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzUc8i/btsMkwMIGQv/ldfGDrWDBqEu8tmtc1dlP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzUc8i%2FbtsMkwMIGQv%2FldfGDrWDBqEu8tmtc1dlP0%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;773&quot; height=&quot;583&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;583&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4b791678-ecf6-4850-b501-92ccc5892716&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-69ed185b-f677-4e36-8041-0b758d9f8444&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2748e130-ba6f-4aff-be46-02c8a98b4e3a&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 키 회전(Key Rotation)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4f124433-e212-4257-bfc4-e99f2b248726&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;키 회전을 하는 이유는 보안상의 이유입니다. 가령 개인키가 노출될 경우 해당 어카운트는 더이상 안전하지 않게 됩니다. 하지만 트랜잭션을 실행할 수 있는 개인키를 변경한다면 어카운트는 안전한 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-04df3a43-844c-4517-acb6-d38b1e2f12db&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;391&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chIEWL/btsMkCF4CWc/YsVkbKyrRVbmIE5RXRRzsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chIEWL/btsMkCF4CWc/YsVkbKyrRVbmIE5RXRRzsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chIEWL/btsMkCF4CWc/YsVkbKyrRVbmIE5RXRRzsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchIEWL%2FbtsMkCF4CWc%2FYsVkbKyrRVbmIE5RXRRzsk%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;296&quot; height=&quot;391&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;391&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div id=&quot;ssp-adcontent-1&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8b6793e8-1b85-40ad-ba47-b33027fcee42&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1660e1bb-c5c9-46c8-945c-8ce22d17fd39&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 Changed Private Key로 어카운트의 개인키를 변경한다면 기존의 Private Key는 Address로 파생할때만 사용가능하며, &lt;/span&gt;&lt;span style=&quot;color: #cd8bc0;&quot;&gt;&lt;b&gt;트랜잭션 서명&lt;/b&gt;&lt;/span&gt;&lt;span&gt;시에는 &lt;/span&gt;&lt;span style=&quot;color: #cd8bc0;&quot;&gt;&lt;b&gt;Changed Private Key&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 사용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c6fead41-4079-4f63-bb8a-f19f8fe8c2f2&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bb1bd7fe-d4eb-445a-9e0b-b22d8415ce38&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 악용&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d4033c5e-9758-4fb0-9d46-a88efdb726e3&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 multi sig와 key rotation을 알아보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-40b4219b-3428-4707-bb8d-816f8438582e&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-51d22fb8-fb8d-4c4b-bc8a-387414b4c6cc&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그렇다면 이 둘을 이용하여 어떻게 사기를 칠 수 있는지 알아보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-94b21d45-6250-4ba3-88a4-c9705fb7096a&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ba459f61-1582-4848-994f-4a7df7b10913&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;어카운트는 다음과 같이 &lt;/span&gt;&lt;span style=&quot;color: #00bfb5;&quot;&gt;&lt;b&gt;multi-sig&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #141414;&quot;&gt; or &lt;/span&gt;&lt;span style=&quot;color: #cd8bc0;&quot;&gt;&lt;b&gt;key rotation&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #141414;&quot;&gt;된 어카운트를 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;낚시 계정(피싱 계정)&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #141414;&quot;&gt;이라고 표현하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-90696761-c68c-4331-9aee-6a204817c428&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uJTDS/btsMma9o53I/OKQksjhmhKHqwHXQ1YtwPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uJTDS/btsMma9o53I/OKQksjhmhKHqwHXQ1YtwPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uJTDS/btsMma9o53I/OKQksjhmhKHqwHXQ1YtwPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuJTDS%2FbtsMma9o53I%2FOKQksjhmhKHqwHXQ1YtwPk%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;536&quot; height=&quot;311&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-18a062e9-abf5-430e-8d83-7876b0163bac&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;391&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sNSOT/btsMkz3AlGN/kwpiEDY105IWEeJ7FNKTN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sNSOT/btsMkz3AlGN/kwpiEDY105IWEeJ7FNKTN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sNSOT/btsMkz3AlGN/kwpiEDY105IWEeJ7FNKTN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsNSOT%2FbtsMkz3AlGN%2FkwpiEDY105IWEeJ7FNKTN1%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;296&quot; height=&quot;391&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;391&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1dcea699-0144-44a0-963e-19cc0617a3e1&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6185d21f-f8d9-4ff2-84cc-e97ca46409c9&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;악용 사례자는 낚시 계정의 원래의 private key를 피해자들에게 뿌립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3ce67a0f-82ed-43e2-9dfa-230b8f704de2&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8948b139-2183-4ff6-a965-de1184a6cee9&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bunNnf/btsMkxkBDT8/N9XK49AQzruu3PU2MlFgtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bunNnf/btsMkxkBDT8/N9XK49AQzruu3PU2MlFgtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bunNnf/btsMkxkBDT8/N9XK49AQzruu3PU2MlFgtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbunNnf%2FbtsMkxkBDT8%2FN9XK49AQzruu3PU2MlFgtK%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;773&quot; height=&quot;466&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8c8bcec9-25aa-48cf-ad55-8a19ef3a9310&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-df88a94b-ecea-4c5f-ace1-ec89b868a046&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;이렇게 되면 피해자들은 privatekey를 통해 해당 자산에 접근이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eadf0fc2-3bbb-4daf-84ec-6654442f09db&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eb783acd-79b0-4494-88b8-b4fc10225397&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;하지만 private key만 뿌리면 피해자는 해당 자산에 접근만 가능할 뿐입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a8b167ae-1b36-49ed-b05e-36f7c8426e85&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a2b88a67-6fa6-4f13-abc2-fe6f94c5bca9&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;여기사 악용 사례자는 해당 어카운트에 네이티브 코인(Eth, Apt, Trx)를 0로 만든 다음 USDT를 굉장히 많이 보유하도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-81773536-bcb7-44eb-a666-254c7fa554a0&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dcb0d642-d904-47be-b7f3-2a65c94f7e13&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;피해자들은 해당 어카운트의 개인키를 알고 있기 때문에 네이티브 코인만 있다면 USDT를 본인의 지갑으로 옮길 수 있을거라는 생각을 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8e37112d-a576-4f53-a2e8-005a6eda9639&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vh4nf/btsMlPYKc67/8KLqWBheWVEY8hkfExHCy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vh4nf/btsMlPYKc67/8KLqWBheWVEY8hkfExHCy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vh4nf/btsMlPYKc67/8KLqWBheWVEY8hkfExHCy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVh4nf%2FbtsMlPYKc67%2F8KLqWBheWVEY8hkfExHCy1%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;773&quot; height=&quot;466&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2bbf7ad2-95bd-47ac-b4b2-dec849ab95ca&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;p id=&quot;SE-8a9ed6d4-c442-4255-83a6-623501cf3815&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;피해자들은 낚시 계정에 Native Coin을 전송합니다. 그리고 낚시 계정의 USDT를 본인의 지갑으로 뺴기 위해 악용 사례자에게 받은 Private Key로 서명한 후 트랜잭션을 실행하면 실패하게 됩니다. 악용 사례자는 &lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;Multi Sig( 추가로 등록된) 개인키&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #141414;&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color: #cd8bc0;&quot;&gt;&lt;b&gt; Key Rotation(변경된 키)&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #141414;&quot;&gt;로 피해자가 전송한 Native Coin을 다른 지갑(or 거래소)으로 옮길수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;641&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k1pZb/btsMlD5ckVD/fgYQxCQ7VAOSc7mSWm90K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k1pZb/btsMlD5ckVD/fgYQxCQ7VAOSc7mSWm90K1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k1pZb/btsMlD5ckVD/fgYQxCQ7VAOSc7mSWm90K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk1pZb%2FbtsMlD5ckVD%2FfgYQxCQ7VAOSc7mSWm90K1%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;773&quot; height=&quot;641&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;641&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div id=&quot;SE-5cb46322-a46f-439e-8bf7-39713e4ee6cc&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c4ec5935-b985-435d-9b68-b13d1153e9d8&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1f75caee-3028-4c34-abb0-d4e96944be6c&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;&lt;b&gt;&amp;middot; 실제 사례&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bff8fe04-6bde-4c86-8f96-dfb194977ee8&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;해당 사건은 제가 실제로 겪었던 일입니다. 물론 저는 낚시 계정에 Native Coin을 전송하지 않았습니다. 앞의 개념을 알고 있었고 이를 확인하는 방법을 알았기 때문에 사기에 당하지 않았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f2ffc78b-29dc-4fc6-a085-0834bd7e1470&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a856a76e-561c-4d93-805d-4d8f151aeb5d&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;저는 유튜브 댓글을 통해 다음과 같은 니모닉을 전달받았습니다.(니모닉은 개인키를 생성하는 방법)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-281bb99f-a7b9-456b-8e39-f9c05c14f2e6&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;여기서는 니모닉 = 개인키로 이해해도 충분합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739781688796&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;니모닉 : mistake turkey blossom warfare blade until bachelor fall squeeze today flee guitar 
어카운트: TAy4omTf7uENvTm2QrT22ZY8BvdrjXUKzC&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-77d3421c-53b9-4032-aa5a-c5404fcfcb56&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-768bfaac-115a-4d8a-80c1-58185e1afb46&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;니모닉을 알려주는 이유는 다음과 같았습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-09b9906b-19ff-4640-b832-8b05304dfb7d&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;&lt;b&gt;&quot;USDT를 가지고 있는 어카운트가 있다 해당 어카운트의 니모닉은 xxx 이며, 이를 거래소로 옮기려고 한다. 도와달라&quot;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #141414;&quot;&gt; 라는 형태의 메시지와 함께 니모닉을 알려줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c95ccf2d-75fb-47a0-b891-7b5f4db4128b&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2e35fbdc-ebe2-454d-ad4c-bda09ebe7904&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;해당 니모닉은 trx 기반 네트워크에서 USDT를 굉장히 많이 보유하고 있는 어카운트의 개인키입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-20549167-8ed8-4758-8be8-e21541f5287b&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKLD4w/btsMkDkG3iO/1HTTZayFDtzyDWFdXQHFwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKLD4w/btsMkDkG3iO/1HTTZayFDtzyDWFdXQHFwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKLD4w/btsMkDkG3iO/1HTTZayFDtzyDWFdXQHFwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKLD4w%2FbtsMkDkG3iO%2F1HTTZayFDtzyDWFdXQHFwK%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;362&quot; height=&quot;600&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-13fbcc35-ba83-47b4-966d-86d0aa49cdd7&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-603a6f83-fa58-4b48-bdee-d3412a8149b2&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;저는 USDT가 어느 네트워크에서 발행된 USDT인지 찾아보니 tron이었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f24e398c-5308-43b0-84ab-bda12c65ff5a&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;629&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r86C2/btsMlWQ2kGl/sNxAN8kEdNNsW10FWcYhK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r86C2/btsMlWQ2kGl/sNxAN8kEdNNsW10FWcYhK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r86C2/btsMlWQ2kGl/sNxAN8kEdNNsW10FWcYhK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr86C2%2FbtsMlWQ2kGl%2FsNxAN8kEdNNsW10FWcYhK0%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;773&quot; height=&quot;629&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;629&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f64bed60-18e8-49bc-8be2-039f25999b89&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-76871058-2bf9-43be-8bbd-5242d560a629&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;여기서 저는 해당 잔액을 확인함과 동시에 트랜잭션 목록이 눈에띄었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b6bfdd9d-1edb-4785-b706-b3cdeeb37167&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-365403cd-6ac8-4a3d-bdde-2948e6a9dd00&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;아니 나에게 전송하는 방법을 물어봤는데 이미 전송 내역이 있다는 점이 매우 이상했습니다. 그래서 해당 어카운트의 Permission을 확인해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7c0dacfa-25a9-4041-bd7b-8cb9986b5e8e&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-71d79401-b48c-46c4-a19d-cca396244986&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;어카운트의 주소와 Permission의 주소가 다르게 나옵니다. 즉 해당 어카운트로 TRX를 전송하더라도 악용 사례자가 공유한 니모닉(개인키)를 이용하여 USDT를 전송할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-60197e3b-47ac-4b99-a35b-4d3267809861&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eoJQWX/btsMkrx0dM3/EYkae4RcbTcyDIBU4wjjw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eoJQWX/btsMkrx0dM3/EYkae4RcbTcyDIBU4wjjw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eoJQWX/btsMkrx0dM3/EYkae4RcbTcyDIBU4wjjw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeoJQWX%2FbtsMkrx0dM3%2FEYkae4RcbTcyDIBU4wjjw0%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;773&quot; height=&quot;551&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-56c3e2df-4468-4f7c-9203-46a6a898a9a1&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9d6dda1e-b65c-4a85-9810-1287396d24a1&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a7f43b18-ff48-41c0-b262-97f59538a308&quot; style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141414;&quot;&gt;aptos의 경우도 Multi sig어카운트와 Key Rotation 모두 지원하며 Key Rotation은 다음과 같이 exploer에서 [resources] - authentication_key와 어카운트 주소가 동일한지 다른지로 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-77a328a0-34a9-4272-bc14-86844aa0bda5&quot; style=&quot;background-color: #ffffff; color: #666666; text-align: left;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;583&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BbrQw/btsMkMBP2PK/0VKSq0KNEIGylOjuKMGCUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BbrQw/btsMkMBP2PK/0VKSq0KNEIGylOjuKMGCUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BbrQw/btsMkMBP2PK/0VKSq0KNEIGylOjuKMGCUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBbrQw%2FbtsMkMBP2PK%2F0VKSq0KNEIGylOjuKMGCUk%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;773&quot; height=&quot;583&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;583&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>Block</category>
      <category>blockchain</category>
      <category>Chain</category>
      <category>블록체인</category>
      <category>사기</category>
      <category>사례자</category>
      <category>악용</category>
      <category>피해자</category>
      <category>해킹</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/102</guid>
      <comments>https://meongae.tistory.com/102#entry102comment</comments>
      <pubDate>Mon, 17 Feb 2025 17:41:59 +0900</pubDate>
    </item>
    <item>
      <title>[github] 원격 저장소에 있는 브랜치를 로컬로 가져오는 방법</title>
      <link>https://meongae.tistory.com/101</link>
      <description>&lt;div id=&quot;SE-250e884c-0ce9-48e2-9673-730f7672e964&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9ca87c98-3fb2-4170-aefc-bc50d922768f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;안녕하세요. 멍개입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-689a641d-b0e0-4e71-94bc-970b445ee061&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;로컬에 없는 원격 저장소에 존재하는 브랜치를 로컬로 가져오는 방법을 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4ee74b10-f0f2-46ea-b270-e248a519d92a&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 원격 저장소 이력 확인&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-fc71156f-ed18-41aa-b826-7869722820c7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원격 저장소에 있는 브랜치 정보를 로컬로 가져옵니다 이떄 브랜치를 병합하진 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1662464772549&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ git remote update&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-94c95dfc-2a52-48e3-bc06-4a9dde23cad5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;remote update를 하게되면 원격 저장소에 있는 브랜치들을 로컬로 가져옵니다. &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4c9d9126-2e8c-4e50-9929-1ed322f57c11&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 브랜치 확인&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-b2314ec9-0258-43b2-92fe-a71248bca1f7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 가져온 브랜치는 git branch로는 조회되지 않습니다. 다음과 같이 조회해야 원격 저장소에서 가져온 브랜치를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-83d372b5-e055-4e4b-b4a4-5c159345166c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-94c95dfc-2a52-48e3-bc06-4a9dde23cad5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4964bf8e-781f-48ca-8f49-cd0e34b28848&quot;&gt;
&lt;pre id=&quot;code_1662464785309&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ git branch -r  # git branch -a


remote/origin/dev
remote/origin/feature1
remote/origin/feature2
remote/origin/feature3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2a3f2b01-95c0-4566-a935-7d25d6f13e51&quot;&gt;
&lt;p id=&quot;SE-a992cc38-1d6f-4046-9223-1e65c3ebe754&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원격 저장소에서 가져온 브랜치는 &lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;remote/origin/브랜치이름&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 형태로 표시됩니다. &lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-45a30d92-0016-4eb1-8983-2780866bdef9&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 체크아웃&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-b7d0e564-47d4-4714-98a0-00289725e838&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;remote/origin/dev로 표시된 항목은 로컬엔 없지만 원격 저장소에 dev 브랜치가 존재한다는 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e97a5c2a-1b3b-4e63-930a-510c06866663&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원격 브랜치로 체크아웃하기 위해 -t 옵션을 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ff72d9a3-0f54-4733-8df1-337e40b84700&quot;&gt;
&lt;pre id=&quot;code_1662464825956&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ git checkout -t [remote/origin/브랜치이름]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-526018c2-5919-4905-85ad-63487a608ffb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f1b32365-f7e4-4925-8b80-480b88dc0311&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 원격 저장소의 dev 브랜치를 로컬에서 체크아웃 하기위해선 다음과 같이 입력하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c815ae19-d29e-447a-ac70-e2f26f2a8d46&quot;&gt;
&lt;pre id=&quot;code_1662464830588&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ git checkout -t remote/origin/dev&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a1351c94-e582-4140-970f-876447a3cea2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-860f3fca-a682-409f-b7de-e876703ec51e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원격 저장소에 있는 dev 브랜치를 로컬에서 체크아웃하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>서버/깃 &amp;amp; 깃허브</category>
      <category>Branch</category>
      <category>CheckOut</category>
      <category>git</category>
      <category>github</category>
      <category>깃</category>
      <category>깃허브</category>
      <category>브랜치</category>
      <category>체크아웃</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/101</guid>
      <comments>https://meongae.tistory.com/101#entry101comment</comments>
      <pubDate>Tue, 6 Sep 2022 20:47:28 +0900</pubDate>
    </item>
    <item>
      <title>멍개 저작권 등록 및 굿즈제작</title>
      <link>https://meongae.tistory.com/notice/100</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;▶&lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://www.oround.com/product/367009?options=T00088,T00095,T00033,T00207&amp;amp;defaultOptions=T00088,T00095&amp;amp;prearea=/mung&quot;&gt; 핸드폰 케이스 - 젤리&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ad4b4c29-19e1-4821-9942-038a2d6d06cf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;▶ &lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://www.oround.com/product/366994?options=T00090,T00095,T00033&amp;amp;defaultOptions=T00095&amp;amp;prearea=/mung&quot;&gt;핸드폰 케이스 - 하드&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4e4eed4d-2fbd-4368-8578-ed0bcd79ab3d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;▶ &lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://www.oround.com/product/366993?options=T00001,T00033&amp;amp;defaultOptions=T00001&amp;amp;prearea=/mung&quot;&gt;버즈 케이스&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7a80877d-5161-4181-9b13-a468eb9cde20&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;▶ &lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://www.oround.com/product/366990?options=T00001,T00033&amp;amp;defaultOptions=T00001&amp;amp;prearea=/mung&quot;&gt;에어팟 케이스&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c5396a61-aa7a-4624-afe6-05eb14a11605&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;▶ &lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://www.oround.com/product/366992?options=T00058,T00065,T00107,T00122,T00032&amp;amp;defaultOptions=T00058,T00032&amp;amp;prearea=/mung&quot;&gt;아크릴키링&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2033c705-b196-4e85-bc72-cce43f1c9d0b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-961d1b38-8d54-44d5-b112-277c374e6793&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.oround.com/mung&quot;&gt;https://www.oround.com/mung&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1662021260410&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;selleb17500의 그라운드 : 감탄 굿즈 마켓 oround&quot; data-og-description=&quot;오라운드 selleb17500의 그라운드에 오신것을 환영합니다. 컬렉션과 기획전, 리뷰를 한눈에 확인해보세요.&quot; data-og-host=&quot;www.oround.com:443&quot; data-og-source-url=&quot;https://www.oround.com/mung&quot; data-og-url=&quot;https://oround.com/mung&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.oround.com/mung&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.oround.com/mung&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;selleb17500의 그라운드 : 감탄 굿즈 마켓 oround&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;오라운드 selleb17500의 그라운드에 오신것을 환영합니다. 컬렉션과 기획전, 리뷰를 한눈에 확인해보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.oround.com:443&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 핸드폰 케이스 - 하드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-d80fa537-266f-49ea-a6c3-7c4d5400a3e0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;갤럭시S21울트라, 갤럭시S21, 갤럭시S21+, 갤럭시S22, 갤럭시S22+,갤럭시S22울트라, 아이폰11, 아이폰13프로맥스, 아이폰12미니, 아이폰12프로, 아이폰12, 아이폰13미니, 아이폰13프로맥스, 아이폰13프로, 아이폰13, &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8845f507-ff34-4128-b2f3-ab5c2c699367&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-71655c5c-f8ff-477d-ac43-4b154ca71028&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 핸드폰 케이스 = 젤리&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-ee83f536-dceb-4202-aaed-c5aad6a17e4e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;갤럭시S20+, 갤럭시S20, 갤럭시노트20울트라, 갤럭시노트, 갤럭시S20울트라, 갤럭시S21, 갤럭시S21+, 갤럭시S21울트라, 갤럭시S22, 갤럭시S22+, 갤럭시S22울트라, 아이폰11프로맥스, 아이폰11프로, 아이폰11, 아이폰XS, 아이폰12미니, 아이폰12프로맥스, 아이폰12, 아이폰12프로, 아이폰13미니, 아이폰13프로맥스, 아이폰13프로&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;저작권 등록증&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20220901＿120211.jpeg&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;1031&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4P7uT/btrK9acLHVf/iyUzX2G61cpAkxf7aqZNh0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4P7uT/btrK9acLHVf/iyUzX2G61cpAkxf7aqZNh0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4P7uT/btrK9acLHVf/iyUzX2G61cpAkxf7aqZNh0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4P7uT%2FbtrK9acLHVf%2FiyUzX2G61cpAkxf7aqZNh0%2Fimg.jpg&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;773&quot; height=&quot;1031&quot; data-filename=&quot;20220901＿120211.jpeg&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;1031&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&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;</description>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/notice/100</guid>
      <pubDate>Thu, 1 Sep 2022 17:35:42 +0900</pubDate>
    </item>
    <item>
      <title>[nestjs] 스웨거 사용시 주의사항 - 순환참조 에러</title>
      <link>https://meongae.tistory.com/99</link>
      <description>&lt;div id=&quot;SE-238206a2-d3d7-4d24-9bcf-6d03e6fa3739&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b90f61c8-d327-4199-9cf3-c1a134013335&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nestjs에서 스웨거 사용시 주의사항을 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-133c9439-4de7-49c8-bc44-978a0abf552e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b308143e-f4f8-453d-8d9f-82ad286269b0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스웨거를 사용하다보면 다음과 같은 에러가 발생할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7ddaaf84-c63a-44a2-856a-ea45a2cd98da&quot;&gt;
&lt;pre id=&quot;code_1661692449126&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:170
            throw new Error(`A circular dependency has been detected (property key: &quot;${key}&quot;). Please, make sure that each side of a bidirectional relationships are using lazy resolvers (&quot;type: () =&amp;gt; ClassType&quot;).`);
                  ^
Error: A circular dependency has been detected (property key: &quot;user&quot;). Please, make sure that each side of a bidirectional relationships are using lazy resolvers (&quot;type: () =&amp;gt; ClassType&quot;).
    at SchemaObjectFactory.createNotBuiltInTypeReference (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:170:19)
    at SchemaObjectFactory.createSchemaMetadata (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:280:25)
    at SchemaObjectFactory.mergePropertyWithMetadata (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:122:21)
    at /Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:79:35
    at Array.map (&amp;lt;anonymous&amp;gt;)
    at SchemaObjectFactory.extractPropertiesFromType (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:78:52)
    at SchemaObjectFactory.createQueryOrParamSchema (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:57:45)
    at /Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:31:29
    at Array.map (&amp;lt;anonymous&amp;gt;)
    at SchemaObjectFactory.createFromModel (/Users/jeongtaepark/Desktop/node_modules/@nestjs/swagger/dist/services/schema-object-factory.js:20:45)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-637a00a7-a1a8-47a0-afd6-70aaca11218a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7mevl/btrKHcCHk5d/SCe9viWTPGJ7ZAFexAT4Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7mevl/btrKHcCHk5d/SCe9viWTPGJ7ZAFexAT4Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7mevl/btrKHcCHk5d/SCe9viWTPGJ7ZAFexAT4Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7mevl%2FbtrKHcCHk5d%2FSCe9viWTPGJ7ZAFexAT4Yk%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;773&quot; height=&quot;238&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dd827c20-aa06-447e-b0c4-30ea1b04202f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4dbb7ff3-cc6d-40cd-8d95-82831b751433&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 에러가 발생하는 케이스를 만들어보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c4b11b53-a119-4c15-a535-09d52849a355&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-42e0ac51-cc57-428c-9e7d-c504f35ff938&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어서 유저와 게시글 관계를 정의할 때 다음과 같이 데이터를 모델링합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4833b05f-f310-4f3d-b8ff-0d000f6a18da&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-ce51d47d-ba0a-4b8a-91c6-69ed608e4ab6&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 유저 DTO&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-07c4c5b2-c15e-472f-9316-c939acef4595&quot;&gt;
&lt;pre id=&quot;code_1661692486065&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ApiProperty } from &quot;@nestjs/swagger&quot;;

import { PostDto } from &quot;./post.dto&quot;;

export class UserDto {
  @ApiProperty({ type : Number })
  id: number;
  
  @ApiProperty({ type : String })
  name: string;

  @ApiProperty({ type : [PostDto] })
  posts: [PostDto];
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-677a3daf-4e42-4b28-8bea-ac936a348a06&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-60127b2e-44f8-4fe6-beb3-4df6dd05f04b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;유저는 다수의 게시글을 가질 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-042cc720-e23f-4e87-8e3c-ce768193e635&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 게시글 DTO&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fee89ac0-50b2-4134-bc1b-92768a088192&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f98884e-15ec-4021-a6f9-38adae09d0fe&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661692494102&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ApiProperty } from &quot;@nestjs/swagger&quot;;

import { UserDto } from &quot;./user.dto&quot;;

export class PostDto {
  @ApiProperty({ type : Number })
  id: number;
  
  @ApiProperty({ type : String })
  title: string;

  @ApiProperty({ type : UserDto })
  user: UserDto;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-897506ae-2a2c-4a64-ad6f-7cbf24fd7e02&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하나의 게시글은 하나의 유저를 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-42d996a4-47a0-488b-a56f-eb58f56d299f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 user와 post는 서로 순환참조 관계를 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d942ab8e-c149-48db-b22a-2a24f5fb1013&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-b4fd758d-ebce-40bb-89f5-02fb6f5b3944&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 해결방법&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-173677dc-d48a-4ae8-90ed-35677295f63c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스웨거의 ApiProperty는 이런 순환참조를 대비하여&lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt; lazy loading&lt;/span&gt;&lt;span&gt;을 이용하합니다. 바로 @ApiProperty는 type을 전달할 때 함수의 반환값을 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-c87b8fdc-569b-4972-bd97-b00bc1681a1c&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 유저 DTO&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e98fa20e-cb2a-4785-a062-45b62d25ed5e&quot;&gt;
&lt;pre id=&quot;code_1661692502339&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ApiProperty } from &quot;@nestjs/swagger&quot;;

import { PostDto } from &quot;./post.dto&quot;;

export class UserDto {
  @ApiProperty({ type : Number })
  id: number;
  
  @ApiProperty({ type : String })
  name: string;

  @ApiProperty({ type : () =&amp;gt; [PostDto] })
  posts: [PostDto];
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d2c757ba-e957-476a-8c62-83def93f3c7e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-829352a1-57d7-40fe-9a58-4683aaf13ed8&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 게시글 DTO&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-74100cd9-8a19-43ca-8c51-440299e60ae6&quot;&gt;
&lt;pre id=&quot;code_1661692508464&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ApiProperty } from &quot;@nestjs/swagger&quot;;

import { UserDto } from &quot;./user.dto&quot;;

export class PostDto {
  @ApiProperty({ type : Number })
  id: number;
  
  @ApiProperty({ type : String })
  title: string;

  @ApiProperty({ type : () =&amp;gt; UserDto })
  user: UserDto;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-411e5915-1938-4947-9a3c-364c1195baf6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-db55f615-7a18-4883-a845-7bd0b4eeeea2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;함수의 반환값으로 타입을 전달하면 lazy loading이 되기 때문에 스웨거 로드가 정상적으로 이루어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d51b4c27-d328-4fea-995f-4f5bdabbc31a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qCpvK/btrKGOWidQ2/AhjGNITdoxdiSXR9UJ4tM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qCpvK/btrKGOWidQ2/AhjGNITdoxdiSXR9UJ4tM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qCpvK/btrKGOWidQ2/AhjGNITdoxdiSXR9UJ4tM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqCpvK%2FbtrKGOWidQ2%2FAhjGNITdoxdiSXR9UJ4tM1%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;773&quot; height=&quot;483&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8f4de0dc-c4ee-4455-8d01-34d753f124a2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-be841716-9a62-4d32-80d0-862f1cc96e6a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>서버/nodejs</category>
      <category>Control</category>
      <category>Dependency</category>
      <category>Di</category>
      <category>injection</category>
      <category>inversion</category>
      <category>IOC</category>
      <category>역전</category>
      <category>의존성</category>
      <category>제어의역전</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/99</guid>
      <comments>https://meongae.tistory.com/99#entry99comment</comments>
      <pubDate>Mon, 29 Aug 2022 07:50:12 +0900</pubDate>
    </item>
    <item>
      <title>[객체지향원칙] DIP 의존성 역전 - nestjs를 이용하여 todo 구현</title>
      <link>https://meongae.tistory.com/98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=jaGnaygzdJA&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/qmBM6/hyPAAEwPwm/q8IIw4D78iaXK5Agk6vSS0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=424_346_1040_564&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/jaGnaygzdJA&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 영상은 제가 즐겨보는 채널입니다. 해당 채널을 보다보면 최근들어 &lt;/span&gt;&lt;span style=&quot;color: #00b976;&quot;&gt;&lt;b&gt;DI(Dependency Inversion)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에 관련해서 언급을 많이하고 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b8c99b73-8d9c-47e1-a033-caa30fbaf7f2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3c12476f-09dc-46da-9cbf-4b64781cdef2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그렇다면 DI가 머길래 열정적으로 &lt;/span&gt;&lt;span&gt;&lt;b&gt;DI&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 언급하는것일까요? 이번포스트에서는 DI가 무엇인지 살펴보고 DI가 잘 적용된 nestjs 프레임워크를 살펴보면서 왜 DI를 사용해야 하는지 알아보겠습니다. 추가적으로 리액트에서 DI를 넣어보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-17a38209-90e3-400e-92ea-657d578d403a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f43d3239-2a01-42fa-88f2-732b91782b73&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저, 우리는 선행되어야 하는 지식이 있습니다. 이 포스트의 제목에 등작한 &lt;/span&gt;&lt;span style=&quot;color: #ff9300;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;DIP&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;span&gt;부터 시작하여 &lt;/span&gt;&lt;span style=&quot;color: #ff9300;&quot;&gt;&lt;b&gt;DI&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ff9300;&quot;&gt;&lt;b&gt;IoC&lt;/b&gt;&lt;/span&gt;&lt;span&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-f7e411f3-805f-4f6e-8da8-d443604016ad&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-f75ff321-ec66-46ba-a309-1e2a9353029d&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 의존성 역전 원칙이란?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-46393ea6-eafd-42ae-a06e-188b73ca9855&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;의존성 역전 원칙(Dependency Inversion Principle)은 DIP라고도 부릅니다. 의존성 역전 원칙의 사전적 의미는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-50b072f8-0224-4eae-8035-63c1059d37b4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;div&gt;
&lt;p id=&quot;SE-727a9fdd-dd98-499f-bf75-cef3e6069955&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #202122;&quot;&gt;객체 지향 프로그래밍에서 &lt;/span&gt;&lt;span style=&quot;color: #202122;&quot;&gt;&lt;b&gt;의존관계 역전 원칙&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #202122;&quot;&gt;은 소프트웨어 모듈들을 분리하는 특정 형식을 지칭한다. 이 원칙을 따르면, 상위 계층(정책 결정)이 하위 계층(세부 사항)에 의존하는 전통적인 의존관계를 반전(역전)시킴으로써 상위 계층이 하위 계층의 구현으로부터 독립되게 할 수 있다. 이 원칙은 다음과 같은 내용을 담고 있다.&lt;/span&gt;&lt;span style=&quot;color: #0645ad;&quot;&gt;[1]&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-210c93ca-ff7d-4c36-a3dc-4cf816901d4b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0645ad;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-80465fe1-8465-4f0a-9f39-e28fc365e4cf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #00b976;&quot;&gt;&lt;b&gt;첫째, 상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bb684dff-5f90-46da-87f1-7d569f902b20&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #00b976;&quot;&gt;&lt;b&gt;둘째, 추상화는 세부 사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-aa16083f-51fb-4ca6-9ebf-643e380bce3c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #202122;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f534feda-25c6-4c02-ab50-c926834a0d91&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #202122;&quot;&gt;이 원칙은 '상위와 하위 객체 모두가 동일한 추상화에 의존해야 한다'는 객체 지향적 설계의 대원칙을 제공한다.&lt;/span&gt;&lt;span style=&quot;color: #0645ad;&quot;&gt;[2]&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-97f0b1b3-570c-423e-b89c-fe83ad678da0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출처: &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4c8a346d-2b55-4e63-ade1-ac382bfa455f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84_%EC%97%AD%EC%A0%84_%EC%9B%90%EC%B9%99&quot;&gt;https://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EA%B4%80%EA%B3%84_%EC%97%AD%EC%A0%84_%EC%9B%90%EC%B9%99&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0b49e1c4-5bb5-487c-a6e2-2714a60ff7dc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9ee88191-91d1-4415-82c1-ce0fcf4cb5ac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;내용이 상당히 어려워보이죠? 앞의 내용을 한 문장으로 해석하면 인터페이스를 활용하라는 것 입니다. 여기서 &lt;/span&gt;&lt;span&gt;&lt;b&gt;DI&lt;/b&gt;&lt;/span&gt;&lt;span&gt;(방법)와 &lt;/span&gt;&lt;span&gt;&lt;b&gt;IoC(개념)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 나오게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c457b304-f352-47ce-9e58-9e215d72726f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2f9121f3-6e12-43da-9df4-c4f2083e2f96&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DIP는 원칙이며 DI는 DIP를 위해 사용되는 방법이고 IoC는 DI 했을때 발생하는 현상입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-26bb4ecb-0d7f-4fe0-861f-b32eff84dc16&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwZzX5/btrKOhB2419/R3VIe52samMD6PXflxyu9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwZzX5/btrKOhB2419/R3VIe52samMD6PXflxyu9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwZzX5/btrKOhB2419/R3VIe52samMD6PXflxyu9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwZzX5%2FbtrKOhB2419%2FR3VIe52samMD6PXflxyu9k%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;510&quot; height=&quot;390&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7f98ed58-778b-4780-96f0-72cde43334a0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-384a211f-77ff-41b4-900a-e311c4f1749d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자 우선 우리는 DIP에서 &lt;/span&gt;&lt;span style=&quot;color: #ff9300;&quot;&gt;&lt;b&gt;D(Dependency)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;I(Inversion)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 무엇을 의미하는지 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bfe11152-ba3e-4f95-bb4c-4efbeca08085&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-95e6e7a3-bcbb-494c-a16e-11ed26a2046a&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 의존성 주입이란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-46913c09-ee94-474e-a6d2-bab9eb2066f6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 코드를 작성할 때 가장 중요한 점 중 하나로 의존성을 낮추는 것을 의미합니다. 그럼 의존성이 머냐? 의존성이 높다는 코드는 new를 통해 객체를 만드는 행위입니다. 간단한 예시 코드를 살펴보겠습니다. 의존성을 낮추기 위해 의존성을 외부에서 주입을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-65f7bbac-f109-453c-aa5c-e40ac93c26bf&quot;&gt;
&lt;pre id=&quot;code_1661670796162&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MacProByIntel {

}

class Mung {
  mac: MacProByIntel;
  
  buyIntel() {
    this.mac = new MacProByIntel();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1bbc59c1-84cf-4008-8b67-a8a67284af5f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-65126e6f-93af-4e4f-aafe-bdabb9c8ae46&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Mung 클래스는 MacProByIntel을 받을 수 있습니다. 여기서 M1 CPU와 M2 CPU를 구매하는 메서드를 추가해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b5388557-bfbd-4079-ae91-a4c2237dd6a8&quot;&gt;
&lt;pre id=&quot;code_1661670804594&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MacProByIntel {

}
class MacProByM1 {

}
class MacProByM2 {

}

class Mung {
  mac: MacProByIntel;
  
  buyIntel() {
    this.mac = new MacProByIntel();
  }
  
  buyM1() {
    this.mac = new MacProByM1();
  }
  
  buyM2() {
    this.mac = new MacProByM2();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c2c616dd-4b16-4a6c-8f5b-1887be0b6707&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-79c6110d-96fe-486e-9714-d41138a5f0ef&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Mung 클래스에서 MacProByIntel, MacProByM1, MacProByM2를 new하여 직접 객체를 만드는 것을 의존성이 높다고 표현합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d87f6608-f7c4-45bd-90c4-089205cd33e7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-4ef099b1-2d63-4fad-a9bd-75a96f505b6e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 Mung이 상위 모듈이며 Mac이 하위 모듈입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1a3f4c6d-fc95-421c-b90f-a841f3bfe84f&quot;&gt;
&lt;pre id=&quot;code_1661670816065&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MacProByIntel {

}
class MacProByM1 {

}
class MacProByM2 {

}

class Mung {
  mac: MacProByIntel;
  
  buyIntel(mac: MacProByIntel) {
    this.mac = mac;
  }
  
  buyM1(mac: MacProByM1) {
    this.mac = mac;
  }
  
  buyM2(mac: MacProByM2) {
    this.mac = mac;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eca507c9-3049-41a7-b0dc-3669d2bbd90e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f89d2985-83af-40c9-a102-5dff4fe84918&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;객체를 직접 생성하지 않고 객체를 전달받는 형태로 구성이 되면 의존성이 낮아졌다고 합니다. 이런 형태를 의존성 주입이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4dec2a51-a62e-4087-908c-d380001d2d59&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;370&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWPHNR/btrKMo2wLkl/LOT1M1AGDs49dZBkeoIoVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWPHNR/btrKMo2wLkl/LOT1M1AGDs49dZBkeoIoVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWPHNR/btrKMo2wLkl/LOT1M1AGDs49dZBkeoIoVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWPHNR%2FbtrKMo2wLkl%2FLOT1M1AGDs49dZBkeoIoVk%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;370&quot; height=&quot;430&quot; data-origin-width=&quot;370&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f381a12c-8e56-421c-a8e7-8e806690089c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a7ed1f34-5877-490d-a621-35a4b21353bb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-91cc2887-a380-47a1-8323-8347dfce0da9&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 추상화&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-76cd4662-d8d2-4b32-bab0-227b6b134606&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DIP의 정의를 살펴보면 가장 많이 나오는 단어가 추상화입니다. 추상화란 인터페이스를 의미합니다. 즉 객체를 의존하지 말고 추상화를 의존하라는 것을 의미합니다. 여기서 IoC가 발생하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-64c590ba-4415-48f1-9130-e80bd9202082&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7e1d65d3-6613-4bdf-af98-f2a51dce4c28&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 DI는 방법, IoC는 개념이라고 했는데 DI를 통해 IoC가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-408c97bb-c191-4df4-a817-a21eb1060ef9&quot;&gt;
&lt;pre id=&quot;code_1661670833817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Mac {

}

class MacProByIntel implements Mac{

}
class MacProByM1 implements Mac{

}
class MacProByM2 implements Mac{

}

class Mung {
  mac: Mac;
  
  buy (mac: Mac) {
    this.mac = mac
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7d3a5ce8-c1fc-4234-8f19-eef44a94bf01&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d352e10d-b760-43b5-bee1-e4670a8e0660&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 우리는 추상화에 의존했다고 표현합니다. 하위모듈인 MacProByIntel, MacProByM1, MacProByM2는 인터페이스를 통해 구현되어집니다. 또한 Mung은 각각의 하위모듈이 아닌 추상화 된 Mac 인터페이스를 받도록 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;SE-78d0b157-6b9e-46f2-803e-eccb55eeb8e8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzi8KH/btrKIsq1fqf/WdMWCPK8B9usRhtHc8PZHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzi8KH/btrKIsq1fqf/WdMWCPK8B9usRhtHc8PZHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzi8KH/btrKIsq1fqf/WdMWCPK8B9usRhtHc8PZHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzi8KH%2FbtrKIsq1fqf%2FWdMWCPK8B9usRhtHc8PZHk%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;386&quot; height=&quot;446&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;span&gt;&amp;nbsp;&lt;/span&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caCbVa/btrKHUnLVMl/EIO6gs2mvlkCxM1Csb8FNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caCbVa/btrKHUnLVMl/EIO6gs2mvlkCxM1Csb8FNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caCbVa/btrKHUnLVMl/EIO6gs2mvlkCxM1Csb8FNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaCbVa%2FbtrKHUnLVMl%2FEIO6gs2mvlkCxM1Csb8FNk%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;526&quot; height=&quot;406&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1f380ea0-7397-4d4c-ba1b-22c8483a4dfc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-03cefbac-c207-4230-a7bb-ce03deea0189&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;좌측에서 우측 처럼 화살표의 방향이 바뀌었습니다. 여기서 역전의 의미가 나오게 됩니다. 즉, IoC가 발생한 것 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-70e55819-2c5b-44c1-955c-270eef7707d0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-328b7e2f-9e58-480f-9ca6-efedd4d6c949&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DIP를 정리하면 DI를 이용하여 의존성을 낮추고 인터페이스를 이용하여 IoC 현상이 발생하는 것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7f9b18c8-30b2-4952-b684-93748bf8710b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e3fae8f3-1c0f-4417-a583-1d414b04384b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DIP 원칙을 따르면 OOP 원칙 중 OCP(Open Close Principle)인 개방 폐쇠 원칙을 지킬 수 있습니다. 만약, 애플이 M3, M4, M5를 계속 만들어 낸다면 우리는 Mac 클래스를 상속받은 M3, M4, M5만 만들어 주면 됩니다. 수정에 대해서 기존 코드를 건드리지 않아도 됩니다. 확장은 자유롭고 수정은 폐쇠되어지게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dadbb9d9-dffb-4262-aa1e-7eda9333f9c5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bd912ac0-b598-4c6f-ab0d-0eaac8f1555d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 멍개는 인터페이스(abstract)를 통해 그 구현체(implementation)에 대한 의존성을 가지게 된다고 표현합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-84982386-24dc-473f-bece-58d13f0fa387&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-d291a30f-543b-4fed-b2db-e36f6810a158&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● DI(Dependency Injection)을 통한 개발은 어떻게 진행되나?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-01b0b44d-aa10-4629-88fa-919d7a428a24&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 사용하는 다양한 라이브러리 및 프레임워크는 DI를 위해 컨테이너를 제공합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9c06cbb4-daf0-4333-a81f-111cbf41a1d1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://blog.naver.com/pjt3591oo/222386896479&quot;&gt;https://blog.naver.com/pjt3591oo/222386896479&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661670868208&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[typescript] typedi를 이용하여 Dependency Injection(DI) 이해하기&quot; data-og-description=&quot;안녕하세요 멍개입니다. 타입스크립트의 typedi를 활용하여 DI(Dependency Injection)를 알아보도록 하...&quot; data-og-host=&quot;blog.naver.com&quot; data-og-source-url=&quot;https://blog.naver.com/pjt3591oo/222386896479&quot; data-og-url=&quot;https://blog.naver.com/pjt3591oo/222386896479&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bpbI2b/hyPACoO7ml/ckImVmeoFmn3BnoGE8oiR0/img.png?width=544&amp;amp;height=205&amp;amp;face=0_0_544_205&quot;&gt;&lt;a href=&quot;https://blog.naver.com/pjt3591oo/222386896479&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.naver.com/pjt3591oo/222386896479&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bpbI2b/hyPACoO7ml/ckImVmeoFmn3BnoGE8oiR0/img.png?width=544&amp;amp;height=205&amp;amp;face=0_0_544_205');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[typescript] typedi를 이용하여 Dependency Injection(DI) 이해하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 멍개입니다. 타입스크립트의 typedi를 활용하여 DI(Dependency Injection)를 알아보도록 하...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6b070569-512a-4d28-a4a0-1d6bdfa2803d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-617283e0-7067-41c6-a514-cc9a0e1bb1e9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-37edea04-f92b-42e9-8f5b-f38fb2aa0602&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 스프링, Nestjs, Angular, FastAPI 등이 DI를 지원하는 프레임워크입니다. 해당 프레임워크의 특징은 객체를 관리하는 컨테이너를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-70a372eb-ca20-489e-837a-c9b1e893d2fd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9373d4a6-6556-4545-94ff-bc75cc27f4e9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nestjs를 이용하여 Todo앱을 만들어 보며 DI가 어떤 이점이 있는지 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1e8a3739-7d2d-4ed0-bf4f-033b60182c43&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-236e1327-2a33-45af-8b23-c6e297e62544&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 데이터베이스 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a8f3fc40-21e8-49dc-80ac-166ab001faca&quot;&gt;
&lt;pre id=&quot;code_1661670887354&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker run --name mysql-container -e MYSQL_ROOT_PASSWORD=password -d -p 3306:3306 mysql:5.7&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-82326d48-532d-4020-92ce-12b9e474e522&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8b67b12e-9809-4b25-8c74-d163b1a398f0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음으로 데이터베이스를 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d2d3d592-5a19-4ee9-82c5-ea86356daff8&quot;&gt;
&lt;pre id=&quot;code_1661670898241&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker exec -it mysql-container /bin/bash

$ mysql -u root -ppassword

mysql&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dd69c1c8-2ca6-45f1-ac34-353e4c145ee3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661670912665&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; CREATE DATABASE todo;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-050d01c1-16c5-4fcf-a15e-38d1d361be6d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-1918a417-5d7f-4ac0-932e-a088859ca207&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; nestjs 프로젝트 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-87b72882-2c0c-4188-a5fc-3e87239d62b7&quot;&gt;
&lt;pre id=&quot;code_1661670925001&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ nest new todo&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-68114731-a060-44c6-ba25-d730628f91e3&quot;&gt;
&lt;pre id=&quot;code_1661670931849&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tree . -I node_modules
.
├── README.md
├── nest-cli.json
├── package-lock.json
├── package.json
├── src
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── main.ts
├── test
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json

2 directories, 13 files&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a2b0c079-b4ef-4760-9c33-46a1d8593198&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0aad4695-29aa-4ac0-ab67-096c4004fd2a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nestjs는 module를 컨테이너라고 부릅니다. module을 통해 객체를 등록하게 됩니다. nestjs는 module에 등록된 객체를 컨트롤러나 서비스에게 주입하여 줍니다. 즉, 우리가 new를 직접하지 않소 nestjs가 new된 결과를 주입하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b7081a80-b055-40d8-92a8-ee7bee708193&quot;&gt;
&lt;pre id=&quot;code_1661670942560&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8a875de0-1eee-4988-a02f-4bb8d3b134c0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cdb7c276-db37-4054-885b-4b423c56ac63&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;controllers에 providers에 명시된 항목을 주입합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5e68b88c-0e9b-4458-b962-44d7b5bb9f70&quot;&gt;
&lt;pre id=&quot;code_1661670950129&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8cae317e-cb28-42ed-a5bf-2253b74a4406&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-33808078-f42d-475f-af94-92eb6f0a0658&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nestjs는 AppController에게 AppService를 주입합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-036545e0-1aa1-4771-8a3f-b6f14d2bf30f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-7a8bd869-535a-4375-97ce-1ca1d49d9a06&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 필요 라이브러리 설치&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-39b35d7c-a123-49cc-a0d2-1797fddf8e78&quot;&gt;
&lt;pre id=&quot;code_1661670965720&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save typeorm mysql2 @nestjs/typeorm&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a73eeb5d-3699-40d8-aa50-90502f0d0bf7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-2a0eb3a4-26a5-4923-8901-dd6b34b4766c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 데이터베이스 모듈 만들기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-8f94a8ae-5730-4b8a-b902-b7185e031b59&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nestjs는 필요한 코드를 providers로 생성 후 module을 통해 export 하는 구조로 모듈을 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ed0b2104-08af-461b-925d-bcc76df07899&quot;&gt;
&lt;pre id=&quot;code_1661670982720&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// database/database.providers.ts

import { DataSource } from 'typeorm';

export const databaseProviders = [
  {
    provide: 'DATA_SOURCE',
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        type: 'mysql',
        host: 'localhost',
        port: 3306,
        username: 'root',
        password: 'password',
        database: 'todo',
        entities: [
            __dirname + '/../**/*.entity{.ts,.js}',
        ],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fbc16949-5d0b-469c-b92d-782ce536c00b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8e38fa14-244b-4cab-b959-df9963d37642&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 모듈을 만들어 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0b10deee-4727-46ba-a06d-008cdc5ff4c1&quot;&gt;
&lt;pre id=&quot;code_1661670992532&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// database/database.module.ts

import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders],
})
export class DatabaseModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b8b92727-edb0-4671-84f1-da1d9fa7c8a1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-20fd6e10-f098-4282-a6f7-609ad088b404&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; todo 앱 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-91aaffeb-17d1-40d8-b39a-bd6d9f926b36&quot;&gt;
&lt;pre id=&quot;code_1661671008008&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ nest g module todo
CREATE src/todo/todo.module.ts (81 bytes)
UPDATE src/app.module.ts (308 bytes)

$ nest g service todo
CREATE src/todo/todo.service.spec.ts (446 bytes)
CREATE src/todo/todo.service.ts (88 bytes)
UPDATE src/todo/todo.module.ts (155 bytes)

$ nest g controller todo
CREATE src/todo/todo.controller.spec.ts (478 bytes)
CREATE src/todo/todo.controller.ts (97 bytes)
UPDATE src/todo/todo.module.ts (240 bytes)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6cb7b85b-366e-4b1e-aeff-8dd3d19656ac&quot;&gt;
&lt;pre id=&quot;code_1661671017416&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tree . -I node_modules
.
├── README.md
├── nest-cli.json
├── package-lock.json
├── package.json
├── src
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   ├── database
│   │   ├── database.module.ts
│   │   └── database.providers.ts
│   ├── main.ts
│   └── todo
│       ├── todo.controller.spec.ts
│       ├── todo.controller.ts
│       ├── todo.module.ts
│       ├── todo.service.spec.ts
│       └── todo.service.ts
├── test
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json

4 directories, 20 files&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e86b3a2f-daad-4a72-a347-800de6b40ef9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;243&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0FAza/btrKHemKZVU/Wegn0PKnm8JkNDHJleIRkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0FAza/btrKHemKZVU/Wegn0PKnm8JkNDHJleIRkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0FAza/btrKHemKZVU/Wegn0PKnm8JkNDHJleIRkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0FAza%2FbtrKHemKZVU%2FWegn0PKnm8JkNDHJleIRkk%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;773&quot; height=&quot;243&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;243&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f8df9066-8f92-41f4-b76f-3de6f3ffe92b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-c7dfed96-ee29-4944-8e4b-2b9135d0cdc4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; todo entity 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-d0d2f8e3-de8f-4989-8f44-59f8572bc8bd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;src/todo/entity/todo.entity.ts를 생성하여 다음과 같이 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-490716d1-3ea7-4fcd-a0fd-df0651325a28&quot;&gt;
&lt;pre id=&quot;code_1661671032168&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Todo {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 500 })
  name: string;

  @Column('text')
  description: string;

  @Column('int')
  isComplete: number;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7a7e3b5d-6b11-4799-b63c-d40ef4920303&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d502e0a8-f008-41fc-8a9e-edd8ff0d6488&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 todo 모듈에 등록된 컨트롤러와 프로바이더에서 데이터베이스를 사용할 수 있도록 하겠습니다&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-03883245-c37f-4889-bf9d-284981d474d9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;src/todo/todo.module.ts를 다음과 같이 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-848a87e5-0665-4d99-9824-1c131ad59b9d&quot;&gt;
&lt;pre id=&quot;code_1661671041216&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { TodoService } from './todo.service';
import { TodoController } from './todo.controller';

import { DataSource } from 'typeorm';
import { Todo } from './entity/todo.entity';
import { DatabaseModule } from 'src/database/database.module';

@Module({
  imports: [DatabaseModule],
  providers: [
    {
      provide: 'TODO_REPOSITORY',
      useFactory: (dataSource: DataSource) =&amp;gt; dataSource.getRepository(Todo),
      inject: ['DATA_SOURCE'],
    },
    TodoService
  ],
  controllers: [TodoController]
})
export class TodoModule { }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-03a3b11e-6386-4ce8-aaee-feb570bd4e76&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-3e46f51d-941a-47bf-94ed-991cb5d5a81f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 서비스 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-3253f0e0-4bf2-4fec-bf02-232397c028ff&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서비스는 데이터베이스와 연결된 Todo 레포지토리 객체를 전달받을 수 있습니다. src/todo/todo.service.ts를 다음과 같이 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ce6f6e36-3a47-4c47-ae99-eb3e7e83b153&quot;&gt;
&lt;pre id=&quot;code_1661671058048&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Injectable, Inject } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Todo } from './entity/todo.entity';

@Injectable()
export class TodoService {
  constructor(
    @Inject('TODO_REPOSITORY')
    private todoRepository: Repository&amp;lt;Todo&amp;gt;,
  ) {}

  async findAll(): Promise&amp;lt;Todo[]&amp;gt; {
    return this.todoRepository.find();
  }

  async find(id): Promise&amp;lt;Todo&amp;gt; {
    return this.todoRepository.findOne({where: id});
  }

  async create(todo: Todo): Promise&amp;lt;Todo&amp;gt; {
    return this.todoRepository.save(todo);
  }

  async update(id, todo: Todo): Promise&amp;lt;Todo&amp;gt; {
    await this.todoRepository.update(id, todo);
    return this.todoRepository.findOne({where: id});
  }

  async delete(id): Promise&amp;lt;Todo&amp;gt; {
    const todo = await this.todoRepository.findOne({where: id});
    await this.todoRepository.remove(todo);
    return todo;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6b870e1b-caf1-44d5-bdb3-f8ecb0fb8180&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-74cb93bf-897c-40fd-8051-0e3d7e266130&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자 이제 우리가 해야할 일은? 해당 서비스가 정상적으로 동작하는지 테스트를 해봐야겠죠? 여기서 의존성 주입이 빛을 보게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-37cb5eee-f713-40e4-95bd-389cbbc2dc89&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1453bf5f-9cc6-42d0-a09a-e9753e5565e5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 Entity 타입으로 처리하지면 DTO를 만들어 처리하는것을 권장합니다 (본 글에서는 Entity 타입을 그대로 이용합니다).&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ba5038a8-f88b-41ad-9b29-73c0b301cab0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-41904a08-ae31-4455-9ace-dc3bdce6f93c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; todo 서비스 테스트 하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-08b0c880-cd42-46b7-bcd0-ec229cf746b2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;src/todo/todo.service.spec.ts에 todoService 테스트 코드를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a8a51a17-9dec-4ee0-ba84-9eaed7b7411d&quot;&gt;
&lt;pre id=&quot;code_1661671072135&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Test, TestingModule } from '@nestjs/testing';
import { TodoService } from './todo.service';

describe('TodoService', () =&amp;gt; {
  let service: TodoService;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      providers: [TodoService],
    }).compile();

    service = module.get&amp;lt;TodoService&amp;gt;(TodoService);
  });

  it('should be defined', () =&amp;gt; {
    expect(service).toBeDefined();
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-76919692-0ec4-4845-ba29-1bac5a7eff8c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9d36dbc5-55be-4e4a-abe3-7032e3796898&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 우리는 import로 전달하는 데이터베이스 소스를 원래 연결된 디비가 아닌 모킹된 객체를 만들어 넘길 수 있습니다. 하지만 우리는 sqlite로 연결시키겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f310bfaf-4048-487f-82a2-bd79bbe3429a&quot;&gt;
&lt;pre id=&quot;code_1661671081391&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { Module } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { TodoService } from './todo.service';

import { Todo } from './entity/todo.entity';

const databaseProviders = [
  {
    provide: 'DATA_SOURCE',
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        name: 'todo',
        type: 'sqlite',
        database: './data_sqlite/example.sq3',
        entities: [Todo],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders]
})
export class DatabaseModule {}

describe('TodoService', () =&amp;gt; {
  let service: TodoService;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      imports: [DatabaseModule],
      providers: [
        {
          provide: 'TODO_REPOSITORY',
          useFactory: (dataSource: DataSource) =&amp;gt; dataSource.getRepository(Todo),
          inject: ['DATA_SOURCE'],
        },
        TodoService
      ],
    }).compile();

    service = module.get&amp;lt;TodoService&amp;gt;(TodoService);
  });

  it('should be defined', () =&amp;gt; {
    expect(service).toBeDefined();
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ad6cb072-a4cd-40da-8a35-a98df2fbf2f9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7006d840-4f94-408a-8fdb-f666ff29fda3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;sqlite 사용을 위해 필요한 라이브러리를 다운받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-244730e5-948b-4c0e-bc2d-c06d2d7c39e0&quot;&gt;
&lt;pre id=&quot;code_1661671088207&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install -D sqlite3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6ac03038-ba0b-47d9-b5e1-5cc60578b7b8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0a4a506d-3523-49c2-8c1f-6bcc58f93994&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 package.json의 scripts의 test를 다음과 같이 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d42ae598-9e12-42f0-970b-23199e675b50&quot;&gt;
&lt;pre id=&quot;code_1661671097255&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;script&quot;: {
    &quot;test&quot;: &quot;rm -rf data_sqlite &amp;amp;&amp;amp; jest&quot;,
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c897a32e-8f34-4569-8143-49ab36a19204&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-930a6d0b-2768-4206-a24a-5f7d0476c358&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;전체 테스트 코드는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-91289952-e18e-400d-933a-db637ded0dcd&quot;&gt;
&lt;pre id=&quot;code_1661671107967&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { Module } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { TodoService } from './todo.service';

import { Todo } from './entity/todo.entity';

const databaseProviders = [
  {
    provide: 'DATA_SOURCE',
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        name: 'todo',
        type: 'sqlite',
        database: './data_sqlite/example.sq3',
        entities: [Todo],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders]
})
export class DatabaseModule {}

describe('TodoService', () =&amp;gt; {
  let service: TodoService;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      imports: [DatabaseModule],
      providers: [
        {
          provide: 'TODO_REPOSITORY',
          useFactory: (dataSource: DataSource) =&amp;gt; dataSource.getRepository(Todo),
          inject: ['DATA_SOURCE'],
        },
        TodoService
      ],
    }).compile();

    service = module.get&amp;lt;TodoService&amp;gt;(TodoService);
  });

  it('should be defined', () =&amp;gt; {
    expect(service).toBeDefined();
  });

  it('조회', async () =&amp;gt; {
    const res = await service.findAll();
    expect(res.length).toBe(0);
  })
  
  it('생성', async () =&amp;gt; {
    const todo = new Todo();
    todo.name = '생성';
    todo.description = '생성';
    todo.isComplete = 0;
    await service.create(todo);
    
    const res = await service.findAll();
    expect(res.length).toBe(1);
  })
  
  it('상태변경', async () =&amp;gt; {
    let todo = await service.find(1);
    todo.isComplete = 1
    await service.update(1, todo);

    todo = await service.find(1);

    expect(todo.isComplete).toBe(1);
  })
  
  it('삭제', async () =&amp;gt; {
    await service.delete(1);

    const res = await service.findAll();
    expect(res.length).toBe(0);
  })
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a39a002a-25b3-4c30-bb17-4259af2fdc8e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O9wk9/btrKGOhuyoF/DN3JGCjlNpY6Gn3CKF8Auk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O9wk9/btrKGOhuyoF/DN3JGCjlNpY6Gn3CKF8Auk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O9wk9/btrKGOhuyoF/DN3JGCjlNpY6Gn3CKF8Auk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO9wk9%2FbtrKGOhuyoF%2FDN3JGCjlNpY6Gn3CKF8Auk%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;773&quot; height=&quot;312&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ae86ccd7-afd4-4f21-8557-22bcb23f5200&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-78c3bea8-ef9c-417f-ac1d-11e5c48c79bf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서비스가 원하는 형태로 잘 동작합니다. 또한 테스트 환경과 API가 동작하는 환경에서 완전히 분리된 데이터베이스 소스를 가지기 때문에 테스트를 통해 데이터베이스가 더렵혀지지 않습니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d6fe9fb9-ac8a-4217-86dd-1fc9299fbebb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 한 가지 정보를 알려드리면 sqlite는 bool 타입을 지원하지 않기 때문에 앞에서 entity를 만들때 isComplete를 bool 타입이 아닌 int 타입으로 생성했던겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cc2d74df-d835-4add-b003-7faf0c9cee44&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-acfc509b-668b-41dc-8476-8b08c686f708&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 컨트롤러 만들기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-4513fd72-3f35-4729-a7ce-34e4a9b61cd6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자 이제 해당 서비스를 주입받아 사용자에게 요청을 받고 응답하는 컨트롤러를 만들어봅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-46a4e1cb-e98a-4c1d-a30c-5dd535cbae6c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;파일명: src/todo/todo.controller.ts&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a3ad2009-5dbb-41e7-81cb-5778b288c85a&quot;&gt;
&lt;pre id=&quot;code_1661671124503&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
import { Todo } from './entity/todo.entity';
import { TodoService } from './todo.service';

@Controller('todo')
export class TodoController {
  constructor(
    private readonly todoService: TodoService,
  ) {}

  @Get()
  findAll(): Promise&amp;lt;Todo[]&amp;gt; {
    return this.todoService.findAll();
  }

  @Get(':id')
  find(@Param('id') id): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.find(id);
  }

  @Post()
  create(@Body() todo: Todo): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.create(todo);
  }

  @Put(':id')
  update(@Param('id') id, todo: Todo): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.update(id, todo);
  }

  @Delete(':id')
  delete(@Param('id') id): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.delete(id);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c1c57f18-dedf-411d-bc2e-e65555fe4e6b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1fbb1a23-34ad-4d5d-a783-8ad8723421d6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 해당 컨트롤러가 잘 동작하는지 살펴봐야 겠죠 같은 경로에 있는 todo.controller.spec.ts를 통해 단위 테스트가 가능하고 /test에서 e2e 테스트를 만들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a31cf0ca-4c59-4edf-ab29-18b593ec0119&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;SE-6fd31c2f-89ce-4828-b9d9-bc7f08d6d054&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; todo 컨트롤러 테스트&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a0c08b7e-fc7f-4442-93f7-3127b28066fa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 단위 테스트를 수행하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-95afdde2-0522-47d5-9196-6ddd3303bccb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파일명: src/todo/todo.cotroller.spec.ts&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-820a3ca2-8cb7-4217-8ba1-d3c25c7f22d8&quot;&gt;
&lt;pre id=&quot;code_1661671145575&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Test, TestingModule } from '@nestjs/testing';
import { TodoController } from './todo.controller';

import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { Module } from '@nestjs/common';
import { TodoService } from './todo.service';

import { Todo } from './entity/todo.entity';

const databaseProviders = [
  {
    provide: 'DATA_SOURCE',
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        name: 'todo',
        type: 'sqlite',
        database: './data_sqlite/controller.sq3',
        entities: [Todo],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders]
})
export class DatabaseModule {}

describe('TodoController', () =&amp;gt; {
  let controller: TodoController;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      imports: [DatabaseModule],
      providers: [
        {
          provide: 'TODO_REPOSITORY',
          useFactory: (dataSource: DataSource) =&amp;gt; dataSource.getRepository(Todo),
          inject: ['DATA_SOURCE'],
        },
        TodoService
      ],
      controllers: [TodoController],
    }).compile();

    controller = module.get&amp;lt;TodoController&amp;gt;(TodoController);
  });

  it('should be defined', () =&amp;gt; {
    expect(controller).toBeDefined();
  });

  it('조회', async() =&amp;gt; {
    const res = await controller.findAll();
    expect(res.length).toBe(0);
  })

  it('생성', async () =&amp;gt; {
    const todo = new Todo();
    todo.name = '생성';
    todo.description = '생성';
    todo.isComplete = 0;
    await controller.create(todo);
    
    const res = await controller.findAll();
    expect(res.length).toBe(1);
  })
  
  it('상태변경', async () =&amp;gt; {
    let todo = await controller.find(1);
    todo.isComplete = 1
    await controller.update(1, todo);

    todo = await controller.find(1);

    expect(todo.isComplete).toBe(1);
  })
  
  it('삭제', async () =&amp;gt; {
    await controller.delete(1);

    const res = await controller.findAll();
    expect(res.length).toBe(0);
  })
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9e893b5e-2819-4141-9004-17fe0d5999bb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baKvC0/btrKHx0HvXk/ErTcnfDo6XkNQ4Q5DyeL10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baKvC0/btrKHx0HvXk/ErTcnfDo6XkNQ4Q5DyeL10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baKvC0/btrKHx0HvXk/ErTcnfDo6XkNQ4Q5DyeL10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaKvC0%2FbtrKHx0HvXk%2FErTcnfDo6XkNQ4Q5DyeL10%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;773&quot; height=&quot;264&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5b8e7986-9b0f-49cb-9534-e1ac1fba1c93&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7f593008-2222-4153-a7ff-4e51aee4c74c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이와 마찬가지로 API를 직접 호출하는 e2e 테스트에서도 별도의 데이터베이스 소스를 생성하여 테스트를 진행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7085348a-c0c0-4af5-9ea2-b7774ea73046&quot;&gt;
&lt;pre id=&quot;code_1661671156183&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, Module } from '@nestjs/common';
import * as request from 'supertest';
import { DataSource } from 'typeorm';
import { Todo } from '../src/todo/entity/todo.entity';
import { TodoService } from '../src/todo/todo.service';
import { TodoController } from '../src/todo/todo.controller';

const databaseProviders = [
  {
    provide: 'DATA_SOURCE',
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        name: 'todo',
        type: 'sqlite',
        database: './data_sqlite/e2e.sq3',
        entities: [Todo],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders]
})
export class DatabaseModule {}

describe('AppController (e2e)', () =&amp;gt; {
  let app: INestApplication;

  beforeEach(async () =&amp;gt; {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [DatabaseModule],
      providers: [
        {
          provide: 'TODO_REPOSITORY',
          useFactory: (dataSource: DataSource) =&amp;gt; dataSource.getRepository(Todo),
          inject: ['DATA_SOURCE'],
        },
        TodoService
      ],
      controllers: [TodoController],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/todo (GET)', () =&amp;gt; {
    return request(app.getHttpServer())
      .get('/todo')
      .expect(200)
      .expect([]);
  });

  it('/todo (POST)', () =&amp;gt; {
    return request(app.getHttpServer())
      .post('/todo')
      .send({
        name: '생성',
        description: '생성',
        isComplete: 0,
      })
      .expect(201)
      .expect({
        name: '생성',
        description: '생성',
        isComplete: 0,
      });
  })
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6a9b9ea6-3344-459c-bce2-c50c3aefe196&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fa1609ae-3355-442c-80f9-16776ca82342&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;package.json의 script에서 test:e2e를 다음과 같이 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3f532dde-d91b-494c-bc0e-2f321605bfa0&quot;&gt;
&lt;pre id=&quot;code_1661671162832&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;scripts&quot; :{
    &quot;test:e2e&quot;: &quot;rm -rf data_sqlite &amp;amp;&amp;amp; jest --config ./test/jest-e2e.json&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bd121527-b826-48eb-9972-38504217dbc5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfUebf/btrKGRyARsj/0folzY2nx198Pg4YOSAKV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfUebf/btrKGRyARsj/0folzY2nx198Pg4YOSAKV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfUebf/btrKGRyARsj/0folzY2nx198Pg4YOSAKV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfUebf%2FbtrKGRyARsj%2F0folzY2nx198Pg4YOSAKV1%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;773&quot; height=&quot;334&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d5039487-1c5e-4fd3-b0b0-c1361489f7f8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8183fe2e-4743-4271-99c1-cac7ddeb5aae&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추가적으로 컨트롤러나 서비스는 또 사이드 이펙트가 존재하는 프로바이더를 주입받을 수 있습니다. 이 또한 테스트를 진행할 때 사이드 이펙트가 모킹되거나 스파이를 통해 테스트를 진행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9241eafd-de8b-4d77-bf9a-2b49e416480d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-18c6d1f4-1f14-49c4-9443-b2a7bdeb7667&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 핵심은 DI를 하게되면 코드의 확장성도 좋아지지만 테스트 코드를 작성하기가 매우 쉬워집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c34fc614-b512-444a-90bd-25dddf3eca75&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a733bcb4-35b3-471b-bea8-cc00a64f2b69&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기까지 보면 DIP는 추상화된 인터페이스를 이용하도록 되어있는데 여기서는 그렇게 진행하진 않았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-52078fa2-f1e5-4a53-b2fa-ff49882d370b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-a38f2a86-3d00-4abb-9e75-7cea469c46d8&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 사이드 이펙트가 존재하는 서비스&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-661f9fca-4f6b-4e4b-ae1c-b0247a8abfb1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일반적으로 사이드 이펙트의 대표적인 예시가 네트워크 통신입니다. 여기서는 랜덤값을 반환하는 함수로 대체하여 진행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6f7c98e3-64f7-49b0-b111-276f50bdef03&quot;&gt;
&lt;pre id=&quot;code_1661671175177&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Injectable } from '@nestjs/common';

@Injectable()
export class SideEffectService {
  constructor(
  ) {}

  async getRandom(): Promise&amp;lt;number&amp;gt; {
    return Math.random();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4c2b7255-81ce-4d11-b1e4-3c19cb4ac3fb&quot;&gt;
&lt;pre id=&quot;code_1661671182094&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/sideEffect/sideEffect.module.ts
import { Module } from '@nestjs/common';
import { SideEffectService } from './sideEffect.service';

@Module({
  providers: [{
    provide: 'SIDE_EFFECT_SERVICE',
    useFactory: () =&amp;gt; {
      return SideEffectService;
    }
  }],
  exports: [{
    provide: 'SIDE_EFFECT_SERVICE',
    useFactory: () =&amp;gt; {
      return SideEffectService;
    }
  }],
})
export class SideEffectModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-53e9de21-6157-4c95-a8ca-f90f49cb26e1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b41b48d0-72c0-4236-8ae4-f6bd88859fb6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 이를 todo에서 사용가능하도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6dbc81c5-111c-4324-95dd-88586dcc4fe5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;todo.module.ts에서 해당 모듈을 imports에 추가하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d1745fe3-78ce-4d88-856a-1895ba4b4edb&quot;&gt;
&lt;pre id=&quot;code_1661671191686&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { TodoService } from './todo.service';
import { TodoController } from './todo.controller';

import { DataSource } from 'typeorm';
import { Todo } from './entity/todo.entity';
import { DatabaseModule } from 'src/database/database.module';
import { SideEffectModule } from 'src/sideEffect/sideEffect.module';

@Module({
  imports: [DatabaseModule, SideEffectModule],
  providers: [
    {
      provide: 'TODO_REPOSITORY',
      useFactory: (dataSource: DataSource) =&amp;gt; dataSource.getRepository(Todo),
      inject: ['DATA_SOURCE'],
    },
    TodoService
  ],
  controllers: [TodoController]
})
export class TodoModule { }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bbae0b40-7693-40b2-8100-a805ef2dee0e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f79b938e-14b5-41e5-a3ac-1a6c35a57d4b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;todo.controller.ts에서 SideEffectService를 주입받고 Post() 요청 핸들러인 create()에서 desciption을 앞에서 만든 랜덤값을 추가하여 저장하도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f8c01c7b-4910-46d0-ae6a-571322227f63&quot;&gt;
&lt;pre id=&quot;code_1661671200142&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
import { SideEffectService } from '../sideEffect/sideEffect.service';
import { Todo } from './entity/todo.entity';
import { TodoService } from './todo.service';

@Controller('todo')
export class TodoController {
  constructor(
    private readonly todoService: TodoService,
    @Inject('SIDE_EFFECT_SERVICE') private readonly sideEffectService: SideEffectService,
  ) {}

  @Get()
  findAll(): Promise&amp;lt;Todo[]&amp;gt; {
    return this.todoService.findAll();
  }

  @Get(':id')
  find(@Param('id') id): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.find(id);
  }

  @Post()
  async create(@Body() todo: Todo): Promise&amp;lt;Todo&amp;gt; {
    const random = await this.sideEffectService.getRandom();
    todo.description = `${todo.description} ${random}`;
    return this.todoService.create(todo);
  }

  @Put(':id')
  update(@Param('id') id, todo: Todo): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.update(id, todo);
  }

  @Delete(':id')
  delete(@Param('id') id): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.delete(id);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0a59ab87-6b42-408a-945d-3a738c076c93&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b910ddad-eaf2-4cf9-b8d2-b32e27e3b99f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 친구를 우리는 어떻게 테스트할 수 있을까요? 자 우선 서버를 구동한 후 API 요청을 해보겠습니다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2bd80f11-e798-432d-a9d6-0dc7390b16b8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PZjKc/btrKOHgnMo6/okVtQMECyaTz4xdK1yV6V1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PZjKc/btrKOHgnMo6/okVtQMECyaTz4xdK1yV6V1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PZjKc/btrKOHgnMo6/okVtQMECyaTz4xdK1yV6V1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPZjKc%2FbtrKOHgnMo6%2FokVtQMECyaTz4xdK1yV6V1%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;773&quot; height=&quot;483&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-36b77c1b-10ba-40a0-8ee0-6191a104d02b&quot;&gt;
&lt;pre id=&quot;code_1661671207342&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; SELECT * FROM todo;
+----+------+-------------------------+------------+
| id | name | description             | isComplete |
+----+------+-------------------------+------------+
|  1 | name | test 0.9163431432608733 |          0 |
+----+------+-------------------------+------------+
1 row in set (0.00 sec)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d12edc19-f80f-456a-9f0f-471fd1dd236a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-5c53aafd-1441-4ff3-bb20-10823d1f4070&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 사이드 이펙트 테스트&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-55989587-b598-47ba-8056-2a6fab780b91&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자 이제 우리는 e2e를 통해 SideEffect를 호출해서 우리가 원하는대로 description에 추가해서 저장되는지 테스트를 수행해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c9a34e20-62b3-4a10-80bf-50fbf092ae99&quot;&gt;
&lt;pre id=&quot;code_1661671225558&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, Injectable, Module, Query } from '@nestjs/common';
import * as request from 'supertest';
import { DataSource } from 'typeorm';
import { Todo } from '../src/todo/entity/todo.entity';
import { TodoService } from '../src/todo/todo.service';
import { TodoController } from '../src/todo/todo.controller';

const databaseProviders = [
  {
    provide: 'DATA_SOURCE',
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        name: 'todo',
        type: 'sqlite',
        database: './data_sqlite/e2e.sq3',
        entities: [Todo],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders]
})
class DatabaseModule {}

@Injectable()
class SideEffectService {
  constructor() {}

  async getRandom(): Promise&amp;lt;number&amp;gt; {
    return 11234;
  }
}

@Module({
  providers: [{
    provide: 'SIDE_EFFECT_SERVICE',
    useClass: SideEffectService,
  }],
  exports: [{
    provide: 'SIDE_EFFECT_SERVICE',
    useClass: SideEffectService,
  }],
})
class SideEffectModule{}

describe('AppController (e2e)', () =&amp;gt; {
  let app: INestApplication;

  beforeEach(async () =&amp;gt; {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [DatabaseModule, SideEffectModule],
      providers: [
        {
          provide: 'TODO_REPOSITORY',
          useFactory: (dataSource: DataSource) =&amp;gt; dataSource.getRepository(Todo),
          inject: ['DATA_SOURCE'],
        },
        TodoService, 
      ],
      controllers: [TodoController],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/todo (GET)', () =&amp;gt; {
    return request(app.getHttpServer())
      .get('/todo')
      .expect(200)
      .expect([]);
  });

  it('/todo (POST)', () =&amp;gt; {
    return request(app.getHttpServer())
      .post('/todo')
      .type('application/json')
      .send({
        name: '생성',
        description: '생성',
        isComplete: 0,
      })
      .expect(201)
      .expect({
        name: '생성',
        description: '생성 11234',
        isComplete: 0,
        id: 1
      });
  })
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3a5c5e19-033b-4bea-98b6-5957ce48455b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-957abbbd-0378-4900-bb6c-5ccfafdf10a1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존의 모듈을 만들었던 부분에서 고정된 랜덤값을 반환하는 SideEffectService()를 주입합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6a53a77d-d506-4c31-a0f7-e067f60ec6dd&quot;&gt;
&lt;pre id=&quot;code_1661671233702&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Injectable()
class SideEffectService {
  constructor() {}

  async getRandom(): Promise&amp;lt;number&amp;gt; {
    return 11234;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0f01b6d0-8b43-43d8-9e73-eb25fb03761f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5e626aa7-b9b0-431c-aec6-4c850d643b95&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TodoController는 주입된 서비스를 정상적으로 동작하여 description이 수정되어 저장되는 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7f41ec68-ec0b-4ec4-af9b-d9ebe43b239f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0bf4e830-09ae-4301-a36b-b0bb96906ac2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 네트워크 통신을 하는 부분이라면 존재하는 에러 코드를 반환하도록 모킹한 후 해당 에러코드에 대해서 원하는 방향으로 동작하는지 테스트가 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-833589dc-846c-423b-b898-84ab7bd92dac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8363f774-dd3a-462f-aeef-38ef9e44aad1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;todo.controller.spec도 테스트 코드 수정이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9afdcf25-5b0e-460d-a006-bf385b5274fe&quot;&gt;
&lt;pre id=&quot;code_1661671243142&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Test, TestingModule } from '@nestjs/testing';
import { TodoController } from './todo.controller';

import { DataSource } from 'typeorm';
import { Module } from '@nestjs/common';
import { TodoService } from './todo.service';

import { Todo } from './entity/todo.entity';

const databaseProviders = [
  {
    provide: 'DATA_SOURCE',
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        name: 'todo',
        type: 'sqlite',
        database: './data_sqlite/controller.sq3',
        entities: [Todo],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders]
})
export class DatabaseModule {}

@Module({
  providers: [{
    provide: 'SIDE_EFFECT_SERVICE',
    useClass: SideEffectService,
  }],
  exports: [{
    provide: 'SIDE_EFFECT_SERVICE',
    useClass: SideEffectService,
  }],
})
class SideEffectModule{}

describe('TodoController', () =&amp;gt; {
  let controller: TodoController;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      imports: [DatabaseModule, SideEffectModule],
      providers: [
        {
          provide: 'TODO_REPOSITORY',
          useFactory: (dataSource: DataSource) =&amp;gt; dataSource.getRepository(Todo),
          inject: ['DATA_SOURCE'],
        },
        TodoService
      ],
      controllers: [TodoController],
    }).compile();

    controller = module.get&amp;lt;TodoController&amp;gt;(TodoController);
  });

  it('should be defined', () =&amp;gt; {
    expect(controller).toBeDefined();
  });

  it('조회', async() =&amp;gt; {
    const res = await controller.findAll();
    expect(res.length).toBe(0);
  })

  it('생성', async () =&amp;gt; {
    const todo = new Todo();
    todo.name = '생성';
    todo.description = '생성';
    todo.isComplete = 0;
    await controller.create(todo);
    
    const res = await controller.findAll();
    expect(res.length).toBe(1);
  })
  
  it('상태변경', async () =&amp;gt; {
    let todo = await controller.find(1);
    todo.isComplete = 1
    await controller.update(1, todo);

    todo = await controller.find(1);

    expect(todo.isComplete).toBe(1);
  })
  
  it('삭제', async () =&amp;gt; {
    await controller.delete(1);

    const res = await controller.findAll();
    expect(res.length).toBe(0);
  })
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cff9be56-7ce4-402d-819e-292cd3e13a2f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-2417dcf9-59cd-4ee7-b394-28a040f86006&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; DIP 적용하기 - 방법1&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-b1365459-5125-4234-b879-3f7123c9e1cd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nestjs에선 DIP를 아주 쉽게 적용할 수 있습니다. module에 전달하는 providers에서 provider를 문자열이 아니라 인터페이스를 넣어주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aac12cff-7b4e-497f-8d7a-f0354f87d663&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-193403d8-2234-4cd4-9cb6-00168a10721f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661671255790&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Module({
  providers: [{
    provide: SideEffectService,
    useClass: SideEffectService,
  }],
  exports: [{
    provide: SideEffectService,
    useClass: SideEffectService,
  }],
})
class SideEffectModule{}&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-bc03ffbb-f524-4602-9669-448ed285fc2e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 프로바이더를 주입받는 클래스는 다음과 같이 주입 inject를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-67d0d9b9-3019-4f27-8b95-64aeba683b44&quot;&gt;
&lt;pre id=&quot;code_1661671260855&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  constructor(
    private readonly todoService: TodoService,
    @Inject(SideEffectService) private readonly sideEffectService: SideEffectService,
  ) {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5c4d1f25-09b1-4128-aacb-6e36ae23d706&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-deafcdb2-727f-4a9a-9f7c-a4aa3dcb4540&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 서비스 자체를 넣는 방법보다는 인터페이스와 함께 상수를 정의하여 사용하는 방법을 권장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-464905fc-2c46-4efb-b125-02e326854953&quot;&gt;
&lt;pre id=&quot;code_1661671268030&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/sideEffect/ISideEffect.interface.ts
export const SIDE_EFFECT_TOKEN = &quot;SIDE_EFFECT&quot;;

export interface ISideEffect {
  getRandom:() =&amp;gt; Promise&amp;lt;number&amp;gt;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5f61a8d6-b36c-47b4-916a-3ea05e48b248&quot;&gt;
&lt;pre id=&quot;code_1661671273455&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/sideEffect/sideEffect.service.ts
import { Injectable } from '@nestjs/common';
import { ISideEffect } from './ISideEffect.interface';

@Injectable()
export class SideEffectService implements ISideEffect{
  constructor(
  ) {}

  async getRandom(): Promise&amp;lt;number&amp;gt; {
    return Math.random();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-38e2d03d-9347-4ff0-a3a8-33623014d3d5&quot;&gt;
&lt;pre id=&quot;code_1661671281358&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/sideEffect/sideEffect.module.ts
import { Module } from '@nestjs/common';
import { SIDE_EFFECT_TOKEN } from './ISideEffect.interface';
import { SideEffectService } from './sideEffect.service';

@Module({
  providers: [{
    provide: SIDE_EFFECT_TOKEN,
    useFactory: () =&amp;gt; {
      return SideEffectService;
    }
  }],
  exports: [{
    provide: SIDE_EFFECT_TOKEN,
    useFactory: () =&amp;gt; {
      return SideEffectService;
    }
  }],
})
export class SideEffectModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6312c77e-531b-472a-9aef-72ddcab2a863&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-dc099d22-8e2b-4fe8-abff-1080a1b826c9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이에 따라서 SideEffectService를 주입받는 todo 컨트롤러의 생성자도 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fada8cb2-12fa-4a91-a5be-7f3e606e5123&quot;&gt;
&lt;pre id=&quot;code_1661671290046&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;... 중략

@Controller('todo')
export class TodoController {
  constructor(
    private readonly todoService: TodoService,
    @Inject(SIDE_EFFECT_TOKEN) private readonly sideEffectService: ISideEffect,
  ) {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d3702eab-7e47-475e-99ec-e7c6d7972191&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0212bad2-52f9-4f4f-9c00-38cd0ed31ad3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 테스트 코드에서도 주입 시 provide 이름을 변경해줍니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-da45333b-db36-45c0-a23f-19de9bafa6a2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-5557c62a-1d1f-4b67-a314-47547fb3dafa&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; DIP 적용 - 서비스 그대로 활용&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-32d98380-7ad8-40b0-84b1-8ee9de8b7ebb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 방법으로 한다면 provide를 문자열로 해야하는 단점이 있습니다. 즉, 실수로 이미 사용중인 값을 사용할 수 있는데 이땐 서비스 자체를 provide로 넘기고 @Inject()에 넘겨주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-675d4403-e0f2-40ea-b7ce-7abe224da407&quot;&gt;
&lt;pre id=&quot;code_1661671302189&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/sideEffect/sideEffect.module.ts

import { Module } from '@nestjs/common';
import { SideEffectService } from './sideEffect.service';

@Module({
  providers: [
    {
      provide: SideEffectService,
      useFactory: () =&amp;gt; {
        return SideEffectService;
      },
    },
  ],
  exports: [
    {
      provide: SideEffectService,
      useFactory: () =&amp;gt; {
        return SideEffectService;
      },
    },
  ],
})
export class SideEffectModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3eda714b-6fec-4010-9edd-ffb20ef81bcd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a6617e99-2c3b-49e6-a338-b3055e208b92&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;provide가 바뀌었으니 controller에서 @Inject()를 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ec636534-66e0-45c8-af8f-fb4c366b841f&quot;&gt;
&lt;pre id=&quot;code_1661671310045&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/todo/todo.contoller.ts
import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  Inject,
} from '@nestjs/common';

import { Todo } from './entity/todo.entity';
import { TodoService } from './todo.service';
import { SideEffectService } from '../sideEffect/sideEffect.service';

@Controller('todo')
export class TodoController {
  constructor(
    private readonly todoService: TodoService,
    @Inject(SideEffectService) // 변경
    private readonly sideEffectService: SideEffectService,
  ) {}

  @Get()
  findAll(): Promise&amp;lt;Todo[]&amp;gt; {
    return this.todoService.findAll();
  }

  @Get(':id')
  find(@Param('id') id): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.find(id);
  }

  @Post()
  async create(@Body() todo: Todo): Promise&amp;lt;Todo&amp;gt; {
    const random = await this.sideEffectService.getRandom();
    todo.description = `${todo.description} ${random}`;
    return this.todoService.create(todo);
  }

  @Put(':id')
  update(@Param('id') id, todo: Todo): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.update(id, todo);
  }

  @Delete(':id')
  delete(@Param('id') id): Promise&amp;lt;Todo&amp;gt; {
    return this.todoService.delete(id);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e6ea01bf-1667-458c-9a43-636389aca308&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ffb40b05-18e4-4ae6-8131-f3db871eb8f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 테스트 코드에서도 다음과 같이 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661671321237&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/todo/todo.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { TodoController } from './todo.controller';

import { DataSource } from 'typeorm';
import { Module } from '@nestjs/common';
import { TodoService } from './todo.service';

import { Todo } from './entity/todo.entity';
import { SideEffectService } from '../sideEffect/sideEffect.service';

const databaseProviders = [
  {
    provide: DataSource,
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        name: 'todo',
        type: 'sqlite',
        database: './data_sqlite/controller.sq3',
        entities: [Todo],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders],
})
export class DatabaseModule {}

describe('TodoController', () =&amp;gt; {
  let controller: TodoController;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      imports: [DatabaseModule],
      providers: [
        {
          provide: Todo,
          useFactory: (dataSource: DataSource) =&amp;gt;
            dataSource.getRepository(Todo),
          inject: [DataSource],
        },
        { provide: SideEffectService, useValue: { getRandom: () =&amp;gt; 11234 } },
        TodoService,
      ],
      controllers: [TodoController],
    }).compile();

    controller = module.get&amp;lt;TodoController&amp;gt;(TodoController);
  });

  it('should be defined', () =&amp;gt; {
    expect(controller).toBeDefined();
  });

  it('조회', async () =&amp;gt; {
    const res = await controller.findAll();
    expect(res.length).toBe(0);
  });

  it('생성', async () =&amp;gt; {
    const todo = new Todo();
    todo.name = '생성';
    todo.description = '생성';
    todo.isComplete = 0;
    await controller.create(todo);

    const res = await controller.findAll();
    expect(res.length).toBe(1);
  });

  it('상태변경', async () =&amp;gt; {
    let todo = await controller.find(1);
    todo.isComplete = 1;
    await controller.update(1, todo);

    todo = await controller.find(1);

    expect(todo.isComplete).toBe(1);
  });

  it('삭제', async () =&amp;gt; {
    await controller.delete(1);

    const res = await controller.findAll();
    expect(res.length).toBe(0);
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8260f6a4-698e-4046-9767-9b8a52533f8b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1655725d-f819-43c1-a673-17f80a851426&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-003da388-4fe4-4bb9-acc2-4777b7c271bd&quot;&gt;
&lt;pre id=&quot;code_1661671330431&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// test/todo.e2e-spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, Module } from '@nestjs/common';
import * as request from 'supertest';
import { DataSource } from 'typeorm';
import { Todo } from '../src/todo/entity/todo.entity';
import { TodoService } from '../src/todo/todo.service';
import { TodoController } from '../src/todo/todo.controller';

import { SideEffectService } from '../src/sideEffect/sideEffect.service';

const databaseProviders = [
  {
    provide: DataSource,
    useFactory: async () =&amp;gt; {
      const dataSource = new DataSource({
        name: 'todo',
        type: 'sqlite',
        database: './data_sqlite/e2e.sq3',
        entities: [Todo],
        synchronize: true,
      });

      return dataSource.initialize();
    },
  },
];

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders],
})
class DatabaseModule {}

describe('AppController (e2e)', () =&amp;gt; {
  let app: INestApplication;

  beforeEach(async () =&amp;gt; {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [DatabaseModule],
      providers: [
        {
          provide: Todo,
          useFactory: (dataSource: DataSource) =&amp;gt;
            dataSource.getRepository(Todo),
          inject: [DataSource],
        },
        { provide: SideEffectService, useValue: { getRandom: () =&amp;gt; 11234 } },
        TodoService,
      ],
      controllers: [TodoController],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/todo (GET)', () =&amp;gt; {
    return request(app.getHttpServer()).get('/todo').expect(200).expect([]);
  });

  it('/todo (POST)', () =&amp;gt; {
    return request(app.getHttpServer())
      .post('/todo')
      .type('application/json')
      .send({
        name: '생성',
        description: '생성',
        isComplete: 0,
      })
      .expect(201)
      .expect({
        name: '생성',
        description: '생성 11234',
        isComplete: 0,
        id: 1,
      });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-30bba1bd-0ab7-44cb-830f-76da7fc6d2dd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1011c18c-40b0-431c-b73c-95da0dce3045&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-58a976c6-d2e5-45bd-8f76-bf7dd3d51dfb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/pjt3591oo/nest-todo-sample&quot;&gt;https://github.com/pjt3591oo/nest-todo-sample&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661671335252&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - pjt3591oo/nest-todo-sample: https://blog.naver.com/pjt3591oo/222805317573 샘플코드&quot; data-og-description=&quot;https://blog.naver.com/pjt3591oo/222805317573 샘플코드 - GitHub - pjt3591oo/nest-todo-sample: https://blog.naver.com/pjt3591oo/222805317573 샘플코드&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/pjt3591oo/nest-todo-sample&quot; data-og-url=&quot;https://github.com/pjt3591oo/nest-todo-sample&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/q8Ajc/hyPBQsdRPK/3MmXOOzpaWjPEHW2RjKKk0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/pjt3591oo/nest-todo-sample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/pjt3591oo/nest-todo-sample&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/q8Ajc/hyPBQsdRPK/3MmXOOzpaWjPEHW2RjKKk0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - pjt3591oo/nest-todo-sample: https://blog.naver.com/pjt3591oo/222805317573 샘플코드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://blog.naver.com/pjt3591oo/222805317573 샘플코드 - GitHub - pjt3591oo/nest-todo-sample: https://blog.naver.com/pjt3591oo/222805317573 샘플코드&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>컴퓨터 공학(Computer Science &amp;amp; Engineering))/디자인 패턴</category>
      <category>Control</category>
      <category>Dependency</category>
      <category>Di</category>
      <category>injection</category>
      <category>inversion</category>
      <category>IOC</category>
      <category>역전</category>
      <category>의존성</category>
      <category>제어의역전</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/98</guid>
      <comments>https://meongae.tistory.com/98#entry98comment</comments>
      <pubDate>Sun, 28 Aug 2022 16:22:33 +0900</pubDate>
    </item>
    <item>
      <title>[디자인 패턴] ES6로 구현하는 디자인 패턴</title>
      <link>https://meongae.tistory.com/97</link>
      <description>&lt;div id=&quot;SE-a2240bad-73dc-490b-bebd-7847c23de87c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-25df279b-560c-4a7a-8daa-f215d65e6bd8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;※ 디자인 패턴 종류&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-23aa5d20-7e7f-4a56-8980-4ea74840b2c3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vxce4/btrKGQzH7L3/EMw1G3pJcc6TTL4sCZK3t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vxce4/btrKGQzH7L3/EMw1G3pJcc6TTL4sCZK3t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vxce4/btrKGQzH7L3/EMw1G3pJcc6TTL4sCZK3t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVxce4%2FbtrKGQzH7L3%2FEMw1G3pJcc6TTL4sCZK3t1%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;722&quot; height=&quot;652&quot; data-origin-width=&quot;722&quot; data-origin-height=&quot;652&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5c0f6c59-29e1-4654-9367-7f65fa5e780c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-7c0670ee-2f7f-4366-8958-bd00459e096d&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ff0010; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 생성패턴&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-56c6b8e5-5acd-41e7-89e3-065cfb6f5dd8&quot;&gt;
&lt;pre id=&quot;code_1661669864182&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Constructor
Factory
Abstract Factory
Prototype
Singleton
Builder&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-01cd855a-1aa9-4bbe-a6d9-1ba77b6d5b42&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-69db1490-f084-4fe3-955c-23755e65062c&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 구조 패턴&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-caad1ef5-a825-437e-a59b-9f41e9d90c22&quot;&gt;
&lt;pre id=&quot;code_1661669876303&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Adapter
Composite
Module
Decorator
Facade
Proxy
FlyWeight
Bridge&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-054d7cbc-14ff-43dd-acde-1acdf86a4ff4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-701310a9-c62a-4260-84d6-112e4b3f8ea9&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 행동 패턴&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d07858e4-c64f-4df0-999e-cad7c971493a&quot;&gt;
&lt;pre id=&quot;code_1661669889135&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Chain of Responsibility
Command
Observer
Iterator
Template
Strategy
visitor
state
memento
mediator&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8fd5d14b-af75-4040-8a55-225f159d3909&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-4501e35e-8942-4c57-96dc-566bd83c3c6a&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ff0010; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 생성패턴&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-a1e76de6-177a-44ed-8e52-a27db2c6cbb7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;생성 패턴은 객체를 생성하는 다양한 방법을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7d75f9c2-5a18-4950-9b26-f84aae39d195&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-720ba6b4-53ea-47eb-bf8d-c3bdf67c5d28&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ff0010; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 1. 생성자 패턴&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-77161152-a3fa-4910-8284-2f6092c9060b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;생성자 패턴은 기존에 클래스를 제공하지 않았던 자바스크립트가 ES6에서 &lt;/span&gt;&lt;span&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 키워드 제공을 통해 향상된 패턴&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ab8d5ec1-ca0f-4f2b-ac7d-6ac628abee8b&quot;&gt;
&lt;pre id=&quot;code_1661669915417&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 옛날 스타일
function OldPerson(name, age) {
  this.name = name;
  this.age = age;
  this.getDetails = function () {
    console.log(`[OLD] ${this.name} is ${this.age} years old!`);
  }
}

// 인스턴스 생성
const oldPerson = new OldPerson('John', 20);
oldPerson.say(); // [OLD] Output - &amp;ldquo;John is 20years old!&amp;rdquo;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-496e24ad-72a9-40ad-8b81-06147b8f0b67&quot;&gt;
&lt;pre id=&quot;code_1661669922368&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class NewPerson {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    this.say() = function () {
      console.log(`[NEW] ${this.name} is ${this.age} years old!`);
    };
  }
}

// 인스턴스 생성
const newPerson = new NewPerson('John', 20);
newPerson.say(); // [NEW] Output - &amp;ldquo;John is 20years old!&amp;rdquo;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8ff822b1-d00c-4c82-bc5f-387d0dd4deab&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-38a76a26-f605-45b7-bc13-5cb0ebf392cb&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ff0010; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 2. Factory Pattern(팩토리 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a08880dc-38c4-48bb-a33d-fc3ff3a4688f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;팩토리 패턴은 클래스가 객체를 생성하는 패턴&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-31fd4244-cdfc-4c0b-a4de-50eb6f8cc81f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tjYrA/btrKOh9SrpO/PJ7kNhn5DkAXCUmS3ubhVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tjYrA/btrKOh9SrpO/PJ7kNhn5DkAXCUmS3ubhVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tjYrA/btrKOh9SrpO/PJ7kNhn5DkAXCUmS3ubhVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtjYrA%2FbtrKOh9SrpO%2FPJ7kNhn5DkAXCUmS3ubhVk%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;494&quot; height=&quot;249&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d0780899-cb13-4f65-a700-b4a7c3a51aff&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-aea270a7-e893-4763-a5e5-ce279c4f83f6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Factory 클래스에 의해 생성하는 객체는 동일한 인터페이스를 가져야 함&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c927a178-3d75-4777-ba1a-a96a5e437d71&quot;&gt;
&lt;pre id=&quot;code_1661669936913&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
  constructor() {}
  
  make (type) {
    switch (type) {
      case 'house':
        return new House();
      case 'car':
        return new Car();
      default:
        return false;
    }
  }
}

class House {
  constructor() {}

  say () {
    console.log(`I'm House`);
  }
}

class Car {
  constructor() {}

  say () {
    console.log(`I'm Car`);
  }
}

const person = new Person()

const house = person.make('house')
const car = person.make('car')

house.say() // I'm House
car.say()   // I'm Car&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7a4f0934-ac20-423e-b166-2848b0847711&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-1dc47610-07f9-4817-b4f9-33ed56565029&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ff0010; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 3. Prototype Pattern (프로토타입 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-af33fbde-4f78-4a0b-bb52-e5b288e8e364&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;프로토타입 패턴은 객체의 템플릿을 기반으로 새로운 객체를 만들 수 있다. 프로토타입 패턴은 상속을 기반으로 하지만 JavaScript는 Object의 create() 메소드를 활용하여 손쉽게 구현 가능.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e2ddc2c7-82e7-4031-9695-1a7540b8be95&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZSe6D/btrKIryP3xX/oh90HhFZbSgWeo5RlsuEd0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZSe6D/btrKIryP3xX/oh90HhFZbSgWeo5RlsuEd0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZSe6D/btrKIryP3xX/oh90HhFZbSgWeo5RlsuEd0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZSe6D%2FbtrKIryP3xX%2Foh90HhFZbSgWeo5RlsuEd0%2Fimg.jpg&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;773&quot; height=&quot;541&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-50a1eb7f-67d8-4251-8355-4b3020cf10c7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c33b278d-3d35-45ec-bcad-0cede34e8e69&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서는 json, class로 템플릿을 제공하는 방법을 다뤄봅니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-98add433-6753-4368-9dad-0a83b83d8ec1&quot;&gt;
&lt;pre id=&quot;code_1661669953193&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const car = {
  noOfWheels: 4,
  start() {
    return `start ${this.noOfWheels}`;
  },
  stop() {
    return `stop ${this.noOfWheels}`;
  },
};

const myCar1 = Object.create(car, { owner: { value: 'Mung1' } });
const myCar2 = Object.create(car, { owner: { value: 'Mung2' } });

console.log(myCar1.__proto__ === car); // true
console.log(myCar2.__proto__ === car); // true

myCar2.noOfWheels += 10

console.log(myCar1.start()) // start 4
console.log(myCar1.stop()) // stop 4
console.log(myCar1.noOfWheels) // 4
console.log(myCar1.owner)  // Mung1

console.log(myCar2.noOfWheels) // 14&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a7db15e-26cc-4a15-a6d5-1d7797a7d6c8&quot;&gt;
&lt;pre id=&quot;code_1661669962674&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Car {
  constructor (_wheels) {
    this.noOfWheels = _wheels;
  }
  
  start() {
    return `start ${this.noOfWheels}`;
  }
  
  stop() {
    return `stop ${this.noOfWheels}`;
  }
}

const car = new Car(4);

const cloneCar1 = Object.create(car, { owner: { value: 'Mung1' } });
const cloneCar2 = Object.create(car, { owner: { value: 'Mung2' } });

console.log(cloneCar1.__proto__ === car); // true
console.log(cloneCar2.__proto__ === car); // true

cloneCar2.noOfWheels += 10

console.log(cloneCar1.start()) // start 4
console.log(cloneCar1.stop()) // stop 4
console.log(cloneCar1.noOfWheels) // 4
console.log(cloneCar1.owner)  // Mung1

console.log(cloneCar2.noOfWheels) // 14&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e0d1943a-1853-4293-b21e-65a19203e92c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-88adcec2-b5d4-45d5-b6b8-276788f32671&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ff0010; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 4. Singleton Pattern (싱글톤 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a33ddba5-e0bb-4e44-857a-6ae5fb788f5d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;싱글톤은 하나의 객체만 생성하는 목적으로 사용&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a99cb2f3-6f71-4622-978a-1526df61ae5c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;디비 커넥션 처럼 한 시스템에서 매번 커넥션을 연결할 필요 없을 때 싱글톤을 이용하여 하나의 커넥션만 유지&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9e63b3d0-6743-49ec-b145-64d2df45400c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYQeGa/btrKMFQEutU/gF7VdryuRbxLo7AzkKq7XK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYQeGa/btrKMFQEutU/gF7VdryuRbxLo7AzkKq7XK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYQeGa/btrKMFQEutU/gF7VdryuRbxLo7AzkKq7XK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYQeGa%2FbtrKMFQEutU%2FgF7VdryuRbxLo7AzkKq7XK%2Fimg.jpg&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;573&quot; height=&quot;262&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bcb73fa1-6bf3-4349-8861-f79df09ed068&quot;&gt;
&lt;pre id=&quot;code_1661669978753&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Car {
  constructor (_wheels) {
    this.wheels = _wheels;
  }
  
  setWheels(_n) {
    this.wheels = _n;
  }
}

const Singleton = {
  instance: null,

  getInstance(_param1) {
    if(!this.instance) this.instance = new Car(_param1);
    return this.instance
  },
};

let car1 = Singleton.getInstance(4);
let car2 = Singleton.getInstance(3);
let car3 = Singleton.getInstance(2);

console.log(car1.wheels, car2.wheels, car3.wheels); // 4 4 4
car2.setWheels(10)
console.log(car1.wheels, car2.wheels, car3.wheels); // 10 10 10&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b05b0e28-c4a3-48a1-9ebb-daca4a6a0e23&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-1420f75d-e16b-4d01-ac49-46bf86e7d4e8&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ff0010; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 5. Builder Pattern (빌더 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-27d34a62-c8e5-48ae-88a6-af17c09a20e9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;빌더 패턴은 체이닝 형태를 유지하여 확장성 있는 객체를 만들 수 &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-427ce0a2-d64c-4dd7-81d8-b69f45a47faf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;※ Before&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6800c9ac-b264-4746-8ea8-0cee1abda110&quot;&gt;
&lt;pre id=&quot;code_1661669994314&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Request { 
  constructor(url, data, method) { 
    this.url = url; 
    this.method = method; 
    this.data = data; 
  } 
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-424e5bb1-c864-44dc-8702-65c9341b9326&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4718f8e8-0d3a-46bf-8c21-034053bb182a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;url과 method만 설정하고 싶다면 다음과 같이 객체를 생성할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7245d955-5219-4902-a872-8471b9cca527&quot;&gt;
&lt;pre id=&quot;code_1661670003843&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const request = new Request('http://localhost', {}, method)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d78c0df2-3ee5-45b9-a060-e9fcd14b232f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fc3ecbd8-edd4-4426-a13b-8d6df6d84781&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 data를 반드시 전달해줘야 함 &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eba739e0-8b3c-455f-b1e0-94235f98b105&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b7d10bbc-24fe-4a81-ad67-5cc9a61bccba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;빌더 패턴을 사용하면 전달하지 않아도 될 인자는 전달할 필요 없음&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7a796985-7f59-42c6-ad3d-834da4833791&quot;&gt;
&lt;pre id=&quot;code_1661670013067&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Request { 
  constructor() { 
    this.url = ''; 
    this.method = ''; 
    this.data = null; 
  } 
} 

class RequestBuilder { 
  constructor() { 
    this.request = new Request(); 
  } 
  forUrl(url) { 
    this.request.url = url; 
    return this; 
  } 
  
  useMethod(method) { 
    this.request.method = method; 
    return this; 
  } 
  
  setData(data) { 
    this.request.data = data; 
    return this; 
  } 
  
  build() { 
    return this.request; 
  } 
} 

let getRequest = new RequestBuilder() 
  .forUrl('https://blog.naver.com/pjt3591oo') 
  .useMethod('GET') 
  .build(); 
  
let postRequest = new RequestBuilder() 
    .forUrl('https://blog.naver.com/pjt3591oo') 
    .useMethod('POST') 
    .setData({ id: 'hg', password: 1234 }) 
    .build();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a98426e-ded3-45a4-9306-d072e1ad4302&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2870f18d-04a5-4fee-bf72-478c140edc27&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;한 가지 중요한 점은 속성을 설정하는 메소드는 반드시&lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt; this를 반환&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하여 체이닝이 가능하도록 해야함&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-027cde50-fccd-407b-96ad-338fe1f35573&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-68f0782f-7d1d-4d67-a52f-7cbfdd4e577e&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● Structural Design Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 id=&quot;SE-cac622b1-e441-4a6a-84b2-e5e7dd080317&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 1. Adapter Pattern (어댑터 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-66ffdf9d-8363-4fb0-bf53-f269262e8b3d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;어댑터 패턴은 서로다른 인터페이스 시스템을 맞추기 위해 어댑터를 추가하여 마치 하나의 시스템인 것 처럼 동작하는 패턴&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cf30f2d3-3ed5-4603-a010-478a04f1f64d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rPit2/btrKGP1OmJf/uFgKLi62vsQktavOWTdGx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rPit2/btrKGP1OmJf/uFgKLi62vsQktavOWTdGx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rPit2/btrKGP1OmJf/uFgKLi62vsQktavOWTdGx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrPit2%2FbtrKGP1OmJf%2FuFgKLi62vsQktavOWTdGx1%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;688&quot; height=&quot;410&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ed549b1e-ab94-417d-ae9a-ca76d94d36a5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2c365c47-c2b4-4d24-8561-8eac32c26cbd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Client&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 과거에 만들어진 인터페이스 &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-04a23388-b5b2-4cd9-ae30-3c0fda657cf0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-18ca0646-6ec1-4688-8acd-b7d8fed183a8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Adaptee&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 발전된 형태의 인터페이스&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b251355e-3408-4666-9037-c4d1f6a6f286&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cf98acd8-d54d-4a25-9889-0062de917696&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존의 코드는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Client&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 인터페이스에 맞춰서 개발이 되었기 때문에 새로 개발된 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Adaptee&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 사용하기 위해선 인터페이스를 수정해야 하지만 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Adapter&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 이용하여 기존 코드의 인터페이스 수정없이 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Adaptee&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 사용 할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1b5441d4-2e78-40ae-beed-f674234d89e4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;코드가 복잡해 보일 수 있지만 자세히 보면 이전 클래스 인터페이스를 최신 인터페이스와 호환하기 위해 어댑터 클래스를 추가한 모습입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f5422930-71c4-4ab3-bddb-1633cdf1585f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-77096633-64a4-47ae-936e-265b90d9e9b5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존의 TicketPrice를 TickerAdapter로 사용자 변경없이 사용가능&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-94fb1efe-4093-4adc-98ae-cc2026727216&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b157c0e4-5fd3-4602-9d6c-c73e514e04f2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;어댑터 패턴의 핵심은 기존의 사용중인 인터페이스를 사용자의 큰 변화없이 사용하는 것이 목표&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2b95b91d-b501-42fa-b916-fd16ded0bc7b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4a504746-da95-472d-9b4c-2e074ad182d8&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 2. Composite Pattern (컴포지트 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e4e242d7-4b00-46d0-8c84-3e24d7dfc7dd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컴포지트 패턴은 파티셔닝 JS 디자인 패턴이라고도 불리며 디렉터리(폴더) 구조를 관리하는 모습을 보임&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9711f3a6-906a-4bdd-9900-7f6094cfcfe2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-52c44a82-4846-4569-901f-f4dfc793b5ee&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 모습은 마치 React나 Vue와 같이 컴포넌트를 관리하는 모습을 가짐&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0583f2a8-06df-4981-9712-4cfbae1ed132&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lwp8X/btrKGRFmhNP/UYz12DoWVC2nE8HMMfKEKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lwp8X/btrKGRFmhNP/UYz12DoWVC2nE8HMMfKEKk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lwp8X/btrKGRFmhNP/UYz12DoWVC2nE8HMMfKEKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flwp8X%2FbtrKGRFmhNP%2FUYz12DoWVC2nE8HMMfKEKk%2Fimg.jpg&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;773&quot; height=&quot;636&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-599ad395-98c1-4d6c-8276-301d3ecb9763&quot;&gt;
&lt;pre id=&quot;code_1661670048332&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class File {
  constructor(_name) {
    this.name = _name;
  }

  display () {
    console.log(this.name);
  }
}

class Directory {
  constructor (_name) {
    this.name = _name;
    this.files = [];
  }

  add (file) {
    this.files.push(file);
  }

  remove (_file) {
    let beforeCnt = this.files.length;
    this.files = this.files.filter(file =&amp;gt; file.name !== _file.name);
    let afterCnt = this.files.length;

    return beforeCnt === afterCnt;
  }

  getFileName (_idx) {
    return this.files[_idx].name
  }

  display () {
    console.log(this.name);
    this.files.forEach((file, idx)  =&amp;gt; {
      console.log(`  ${this.getFileName(idx)}`) // file.name
    })
  }
}

const directoryOne = new Directory('Directory One');
const directoryTwo = new Directory('Directory Two');
const directoryThree = new Directory('Directory Three');

const fileOne = new File('File One');
const fileTwo = new File('File Two');
const fileThree = new File('File Three');

directoryOne.add(fileOne);
directoryOne.add(fileTwo);

directoryTwo.add(fileOne);

directoryThree.add(fileOne);
directoryThree.add(fileTwo);
directoryThree.add(fileThree);

directoryOne.display();
directoryTwo.display();
directoryThree.display();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d50cb239-21cf-4f19-a26d-a84fe24a3d61&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-3056fb69-f416-4048-a47d-64dd8d5bf411&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 3. Module Pattern (모듈 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-1bfc68e1-94e1-4ca1-bae8-c38e24f0881f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자바스크립트의 모듈 패턴은 클로저를 이용하여 함수를 마치 클래스처럼 사용하는 기법&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-780e5468-41d9-4114-b44b-f4b3bdd61294&quot;&gt;
&lt;pre id=&quot;code_1661670061525&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function AnimalContainter () {
  const container = [];

  function addAnimal (name) {
    container.push(name);
  }

  function getAllAnimals() {
    return container;
  }

  function removeAnimal(name) {
    const index = container.indexOf(name);
    if(index &amp;lt; 1) {
      throw new Error('Animal not found in container');
    }
    container.splice(index, 1)
  }

  return {
    add: addAnimal,
    get: getAllAnimals,
    remove: removeAnimal
  }
}

  const container = AnimalContainter()

  container.add('Hen')
  container.add('Goat')
  container.add('Sheep')

  console.log(container.get()) // [&quot;Hen&quot;, &quot;Goat&quot;, &quot;Sheep&quot;]
  container.remove('Sheep')
  console.log(container.get()) // [&quot;Hen&quot;, &quot;Goat&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b116ad13-3dc0-4b98-a77f-83eccf8d95e7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4bc78f61-232b-4e3f-ad20-9647618ad22e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;AnimalContainter에서 반환(리턴)된 변수 / 함수만 외부에서 접근하여 사용가능&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-45139a63-3f40-4a8d-80f3-a6a0db7c281d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 4. Decorator Pattern (데코레이터, 장식자 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-2efd8487-3644-430e-8a18-e452a86b3413&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;데코레이터는 코드 재사용을 목적으로 함. 자바스크립트에선 이를 쉽게 구현할 수 있다. 이를 이용하여 동일한 클래스로 만들어진 객체에 다른 동작을 부여할 수 있다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-550fd673-5e9b-4983-8551-5592ff60f9db&quot;&gt;
&lt;pre id=&quot;code_1661670081357&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Vehicle {
  constructor (vehicleType = &quot;car&quot;) {
    this.vehicleType = vehicleType;
    this.model = 'default';
    this.license = '12345-123';
  }
}

const truck = new Vehicle( &quot;truck&quot; );

// 여기서 화살표 함수를 사용하면 this 바인딩이 안되기 떄문에 function 이용
truck.setModel = function( _model ){
    this.model = _model;
};

truck.setColor = function( _color ){
    this.color = _color;
};

truck.setModel( &quot;CAT&quot; );
truck.setColor( &quot;blue&quot; );

console.log( truck );
/*
Vehicle {
  vehicleType: 'truck',
  model: 'CAT',
  license: '12345-123',
  setModel: [Function],
  setColor: [Function],
  color: 'blue'
}
*/

const dump = new Vehicle( &quot;dump&quot; );
console.log(dump) // Vehicle { vehicleType: 'dump', model: 'default', license: '12345-123' }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4cf847b8-1427-4613-9660-42f1b6a65013&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-05731305-efd1-4a2b-9c87-2ee2dc6b5e3f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;truck으로 전달된 변수 truck만 setModel()과 setColor() 메소드 수행 &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e65c502c-9086-4b96-829b-7ad1ab9ca837&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4761e980-c17f-437e-88ca-32cd8a4d111d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 5. Facade Pattern (퍼사드 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-92a1cabd-47a1-4348-97ec-5234a158f198&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;퍼사드 패턴은 내부적으로 복잡한 구조(Subsystem)를 단순화(Facade)하여 외부에 공개하는 패턴&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7d8f80dc-1a0d-4f0f-9e57-9590cae39f00&quot;&gt;
&lt;pre id=&quot;code_1661670098533&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Bank {
  verify (_name, _amount) {
    return true;
  }
}

class Credit {
  get (_name) {
    return true;
  }
}

class Background {
  check (_name) {
    return true;
  }
}

class Mortgage {
  constructor (_name) {
    this.name = _name;
  }
  
  applyFor (amount) {
    let result = &quot;approved&quot;;
    if (!new Bank().verify(this.name, amount)) {
        result = &quot;denied&quot;;
    } else if (!new Credit().get(this.name)) {
        result = &quot;denied&quot;;
    } else if (!new Background().check(this.name)) {
        result = &quot;denied&quot;;
    }
    return `${this.name} has been ${result} for a ${amount} mortgage`
  }
}

const mortgage = new Mortgage(&quot;Joan Templeton&quot;);
const result = mortgage.applyFor(&quot;$100,000&quot;);

console.log(result);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2496e71c-fc17-4332-8df9-ab0747043aa4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ce64347f-6b21-43da-93ef-9ef448254019&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클래스 1, 2, 3에 해당하는 Bank, Credit, Background 클래스로 구현된 기능을 Mortgage의 applyFor 메소드를 통해 제공&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-15621a66-9b26-4f93-abb3-32912e0d0159&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-a91f7fae-9a3b-4260-be63-cdff68b12b51&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 6. Proxy Pattern (프록시 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-f259086d-0aa1-472e-90a3-a887eee3c98b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;프록시 패턴은 접근을 제어하고 비용 절감하며 복잡성을 줄이기 위해 사용&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1d03ac2b-9f45-4d6a-8ac9-39e8fc135ab8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e3811288-8cbc-44ce-a3c1-fc05f00a701e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;프록시는 네트워크 연결, 큰 메모리 객체와 같은 비용이 많이 들거나 복제가 불가능한 리소스 같은 형태에서 사용&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c8265ac6-5c13-4729-822c-cb38da7ee587&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V2sXU/btrKIsq0Dc9/ajvMXKQdLlAc5rOzntKRXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V2sXU/btrKIsq0Dc9/ajvMXKQdLlAc5rOzntKRXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V2sXU/btrKIsq0Dc9/ajvMXKQdLlAc5rOzntKRXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV2sXU%2FbtrKIsq0Dc9%2FajvMXKQdLlAc5rOzntKRXK%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;600&quot; height=&quot;282&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c1c0898a-e6b4-4989-b1fe-aa6eb7684153&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1b78cf92-82d6-4920-b073-63195f0b9533&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 파일을 읽어야 한다면 파일을 직접 읽지 않고 프록시 객체를 통해 접근. 프록시는 반복된 파일 접근에 대해 캐싱 처리 등을 수행할 수 있다. 프록시 패턴을 적용하는 상황은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-015494fc-9469-4697-951f-1ea8010f6c65&quot;&gt;
&lt;pre id=&quot;code_1661670112590&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;가상 프록시: 생성 비용이 높거나 리소스를 많이 사용하는 객체를 위한 프록시
원격 프록시: 원격 객체에 대한 접근 제어
보호 프록시: 민감한 마스터 객체에 대한 접근 권한 제어&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-316bd12c-73d5-4f39-a135-2b69b0a3ac49&quot;&gt;
&lt;pre id=&quot;code_1661670119047&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class FlightListAPI {
  getFlight() {
      // get master list of flights
      console.log('Generating flight List');
  }

  searchFlight (flightDetails) {
      // search through the flight list based on criteria
      console.log('Searching for flight');
  }
  
  addFlight(flightData) {
      // add a new flight to the database
      console.log('Adding new flight to DB');
  }
};
  
class FlightListProxy {
  constructor () {
    this.flightList = new FlightListAPI();
  }
  getFlight() {
    return this.flightList.getFlight();
  }

  searchFlight(flightDetails) {
    return this.flightList.searchFlight(flightDetails);
  }

  addFlight(flightData) {
    return this.flightList.addFlight(flightData);
  }
}
  
console.log(&quot;----------With Proxy----------&quot;)
const proxy = new FlightListProxy()
proxy.getFlight() // Generating flight List&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-53a75da5-e45c-4432-950f-945e145bdcf5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a2e77c70-c13d-4257-9fc9-adaad1e45afb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;FlightListApi를 직접 제어하지 않고 Proxy를 통해 제어&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b4894790-a5c6-47c0-8335-d381833a4b23&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c0f29a57-ef12-4560-a90f-cedff92522ec&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 7. Flyweight Pattern (경량화 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-6904635b-035b-46a1-b2b5-61c5c617b393&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;경량화 패턴은 Cost(비용)이 높은 자원을 공통으로 사용하는 패턴&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-47f0d5fe-aca7-4668-9c4a-f5974e280016&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-77693533-b33d-4742-9a6a-7e89c66d1f99&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;캐시를 목적으로 하는 패턴&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4534d614-b3f5-4597-9cee-99f1c27307f9&quot;&gt;
&lt;pre id=&quot;code_1661670137286&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;자원에 대한 비용이란? 
1. Duplicate Create (반복되는 패턴)
2. Low Frequncy AND Hight Cost About Create (생성 비용이 높지만 자주 사용되지 않는경우)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-883280b1-c514-4d1d-972b-d0678978a1f8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CTY7A/btrKIxlEoCI/K7ulBhd7W9gTK6Cp4RcRD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CTY7A/btrKIxlEoCI/K7ulBhd7W9gTK6Cp4RcRD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CTY7A/btrKIxlEoCI/K7ulBhd7W9gTK6Cp4RcRD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCTY7A%2FbtrKIxlEoCI%2FK7ulBhd7W9gTK6Cp4RcRD1%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;381&quot; height=&quot;151&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ab87bcce-6ca6-421a-9dc6-d7c9668adcf9&quot;&gt;
&lt;pre id=&quot;code_1661670145455&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Flyweight{
  map: {[key: string]: Subject} = {};
 
  getSubject( name: string ): Subject {
    let subject: Subject = this.map[name];

    if(!subject){
      subject = new Subject(name);
      this.map[name] = subject;
    }

    return subject;
  }
}

class Subject{
  name: string;

  constructor( name: string){
    this.name = name;
    console.log(&quot;create : &quot; + name);
  }
}

const flyweight: Flyweight = new Flyweight();

flyweight.getSubject(&quot;a&quot;);
flyweight.getSubject(&quot;a&quot;); // 다시 생성하지 않음
flyweight.getSubject(&quot;b&quot;);
flyweight.getSubject(&quot;b&quot;); // 다시 생성하지 않음

/*
실행결과

create : a
create : b
*/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0d67f324-ad9b-4be3-b4be-bf29d0c4471c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-023a0c32-613f-455a-b867-d05eea430dc5&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #36851e; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 8. Bridge Pattern (브릿지 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-ae40af23-6e52-401d-b9df-fe4479e32e3d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;브릿지 패턴은 기능과 구현을 별도의 클래스로 관리&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6d6ec031-f15c-4aff-95c0-cf560f6011bd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UsBYt/btrKIskeeJf/RmbSkm5eTkk0teSLVOPZJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UsBYt/btrKIskeeJf/RmbSkm5eTkk0teSLVOPZJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UsBYt/btrKIskeeJf/RmbSkm5eTkk0teSLVOPZJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUsBYt%2FbtrKIskeeJf%2FRmbSkm5eTkk0teSLVOPZJK%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;635&quot; height=&quot;345&quot; data-origin-width=&quot;635&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dcdcade3-d98c-42d1-9636-26d0427eff1b&quot;&gt;
&lt;pre id=&quot;code_1661670165895&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Abstraction: 최상위 기능계층, 해당 인스턴스를 통해 구현 메소드 호출
RefindAbstraction: Abstraction을 이용하여 새로운 계층 생성(상속받아 기능확장)

Implementor: Abstraction 기능 구현을 위해 인터페이스
ConcreteImplementor: Implementor를 상속받아 실제기능 구현&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fa920bc8-ebae-4227-b760-24a574422368&quot;&gt;
&lt;pre id=&quot;code_1661670172007&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Implementor: 기능 구현을 위한 인터페이스
interface HuntingHandler {
  find(): void;
  detected(): void;
  attack(): void;
}

// ConcreteImplementor: Implementor를 상속받아 기능 구현
class HuntingMethod1 implements HuntingHandler {
  find(): void {
    console.log('find by HuntingMethod1')
  }
  detected(): void {
    console.log('detected by HuntingMethod1')
  }
  attack(): void {
    console.log('attack by HuntingMethod1')
  }
}

class HuntingMethod2 implements HuntingHandler {
  find(): void {
    console.log('find by HuntingMethod2')
  }
  detected(): void {
    console.log('detected by HuntingMethod2')
  }
  attack(): void {
    console.log('attack by HuntingMethod2')
  }
}

// Abstractor: 기능의 최상위 객체
class Animal {
  hunting: HuntingHandler;

  constructor(hunting: HuntingHandler) {
    this.hunting = hunting
  }

  find() {
    this.hunting.find();
  }
  detected() {
    this.hunting.detected();
  }
  attack() {
    this.hunting.attack();
  }

  hunt() {
    this.find();
    this.detected();
    this.attack();
  }
}

// RefineAbstraction: 최상위 Abstractor 상속받아 실제 클래스 구현
class Tiger extends Animal {
  constructor(hunting: HuntingHandler) {
    super(hunting);
  }

  hunt() {
    super.hunt()
    console.log(&quot;사냥끝~~&quot;);
  }
}

class Bird extends Animal {
  constructor(hunting: HuntingHandler) {
    super(hunting);
  }

  hunt() {
    super.hunt()
    console.log(&quot;사냥끝~~&quot;);
  }
}

const tiger: Animal = new Tiger(new HuntingMethod2());
const bird: Animal = new Bird(new HuntingMethod1());

tiger.hunt();
console.log(&quot;--------------&quot;);
bird.hunt();

/*
실행결과

find by HuntingMethod2
detected by HuntingMethod2
attack by HuntingMethod2
사냥끝~~
--------------
find by HuntingMethod1
detected by HuntingMethod1
attack by HuntingMethod1
사냥끝~~
*/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c6bcc5a4-2cdb-4ca1-9e7b-06b632fdf3b4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-51dc18ce-f622-42cc-8e13-4aa8d5dfe328&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Abstract에 맞는 Implement를 주입하여 의존도를 낮추고 다양한 조합을 만들 수 있다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5589fdc0-a9d9-4d96-9ab3-bea807ef39a5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;773&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9zRvg/btrKMnP3L4Z/LewVOD6Y8Q35OD2B3fF8wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9zRvg/btrKMnP3L4Z/LewVOD6Y8Q35OD2B3fF8wK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9zRvg/btrKMnP3L4Z/LewVOD6Y8Q35OD2B3fF8wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9zRvg%2FbtrKMnP3L4Z%2FLewVOD6Y8Q35OD2B3fF8wK%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;773&quot; height=&quot;773&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;773&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1c562be5-3abf-47ba-9413-14f36b0fb5a9&quot;&gt;
&lt;pre id=&quot;code_1661670184616&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// old system
class TicketPrice {
  request(start, end, overweightLuggage) {
    // 가격 계산 로직
    return &quot;$150.34&quot;;
  }
}

// new interface
class NewTicketPrice {
  login (credentials) {  };
  setStart (start) { };
  setDestination (destination) {  };
  calculate (overweightLuggage) {
    return &quot;$120.20&quot;;
  };
}

// 어댑터
class TicketAdapter {
  constructor (credentials) {
    this.pricing = new NewTicketPrice();
    this.pricing.login(credentials);
  }

  request(start, end, overweightLuggage) {
    this.pricing.setStart(start);
    this.pricing.setDestination(end);
    return this.pricing.calculate(overweightLuggage);
  }
}

var pricing = new TicketPrice();
var credentials = { token: &quot;30a8-6ee1&quot; };
var adapter = new TicketAdapter(credentials);

// original ticket pricing and interface
var price = pricing.request(&quot;Bern&quot;, &quot;London&quot;, 20);
console.log(&quot;Old price: &quot; + price);

// new ticket pricing with adapted interface
price = adapter.request(&quot;Bern&quot;, &quot;London&quot;, 20);
console.log(&quot;New price: &quot; + price);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-71aebe92-842c-4cbb-a9c6-7c2137203b02&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-80662fda-8601-4e0c-a292-e9a35f5472c8&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● Behavioral Design Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 id=&quot;SE-e031cc05-5c84-4373-98d8-ffdafc0b5af5&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 1. Chain of Responsibility Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-f75036c0-3661-41cb-9aeb-8e7a0ed9a0df&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;빌더 패턴을 구현하는 핵심 패턴&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-032d5621-594c-40c0-9e9e-3ea7f3fdf29e&quot;&gt;
&lt;pre id=&quot;code_1661670214088&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Request {
  constructor (_amount) {
    this.amount = _amount;
  }

  get (bill) {
    const count = Math.floor(this.amount / bill);
    this.amount -= count * bill;
    console.log(`Dispense ${count} $${bill} bills`);
    return this;
  }
}

const request = new Request(378); //Requesting amount
request.get(100).get(50).get(20).get(10).get(5).get(1);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7db834a8-6f98-4735-a9b7-2ee46f37ba51&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ed12f656-0cc8-41b4-81d6-2ada8079fd63&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;this를 반환하여 체이닝을 할 수 있도록 함&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-abafe3e9-6924-462d-a81e-c0faa49976cd&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 2. Command Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-68615d12-691f-4056-a70d-5fbac9b979ca&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Command 패턴은 동작이나 작업을 캡술화하는 패턴&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-be89140a-5f56-433a-afc1-61074122c668&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;A라는 클래스를 작업을 하기 위해 A객체를 직접 접근하지 않고 중간 객체를 통해 작업수행&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-155db42c-fc87-43ed-b97c-dc55d628d7d8&quot;&gt;
&lt;pre id=&quot;code_1661670235585&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const calculator = {
  add: function(x, y) {
      return x + y;
  },
  sub: function(x, y) {
      return x - y;
  },
  divide: function(x,y){
      return x/y;
  },
  multiply: function (x,y){
      return x*y;
  }
}

const manager = {
  execute: function(name) {
      if (name in calculator) {
          return calculator[name].apply(calculator, [].slice.call(arguments, 1));
      }
      return false;
  }
}

console.log(manager.execute(&quot;add&quot;, 5, 2)); //  7
console.log(manager.execute(&quot;multiply&quot;, 2, 4)); //  8&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06d33623-cb7f-44c4-92c6-109939db67fe&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-afca5625-4da4-4f21-856d-dc79e5fe1d0e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Command 패턴은 좀 더 견고한 코드를 위해 execute로 수행할 객체를 전달할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-2b39a7d3-e44b-45f8-a0fd-1cb567724b25&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 3. Observer Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-09cbcdd3-f6b3-4444-a474-4ade44f76ed9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Observer 패턴은 관찰중인 객체(Subject)에 발생하는 이벤트에 대해 여러 객체(Observer)에게 알리는 구독 메커니즘 제공&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6b026f56-38ad-4e68-aeea-cf8717389748&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfh9vI/btrKMnWQ4y0/NmI0c43aXCKVshEDsz0eWk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfh9vI/btrKMnWQ4y0/NmI0c43aXCKVshEDsz0eWk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfh9vI/btrKMnWQ4y0/NmI0c43aXCKVshEDsz0eWk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcfh9vI%2FbtrKMnWQ4y0%2FNmI0c43aXCKVshEDsz0eWk%2Fimg.jpg&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;773&quot; height=&quot;287&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-08c471ee-d3e9-43b0-a96f-dca738de8e01&quot;&gt;
&lt;pre id=&quot;code_1661670252466&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Click {
  constructor () {
    this.observers = [];
  }

  subscribe (fn) {
    this.observers.push(fn);
  }

  unsubscribe(fn) {
    this.observers = this.observers.filter( (item) =&amp;gt; item !== fn );
  }

  fire(o, thisObj) {
    let scope = thisObj;
    this.observers.forEach(function(item) {
      item.call(scope, o);
    });
  }
}

const clickHandler = item =&amp;gt; { 
  console.log(&quot;Fired:&quot; +item);
};

const click = new Click();

click.subscribe(clickHandler);
click.fire('event #1');

click.unsubscribe(clickHandler);
click.fire('event #2');

click.subscribe(clickHandler);
click.fire('event #3');

/* 
실행결과

Fired:event #1
Fired:event #3
*/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-70441ac4-d613-438f-a1c4-cf778a58fe69&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-a48fb354-2fa5-4ff3-8e2f-6ea57fec7527&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 4. Iterator Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-724d68c3-c85f-4968-b174-c59de8d7c224&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;반복자 패턴을 통해 순차적으로 접근 가능, 하지만 ES6의 제너레이터를 이용하면 좀 더 편하게 구현 가능&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-30b166f8-e866-4d7b-b638-2d0b3b3f1218&quot;&gt;
&lt;pre id=&quot;code_1661670265434&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const items = [1, &quot;hello&quot;, false, 99.8];

class Iterator {
  constructor(items) {
    this.items = items;
    this.index = 0;
  }

  hasNext(){
    return this.index &amp;lt; this.items.length;
  }

  next(){
    return this.items[this.index++]
  }
}

const iterator =  new Iterator(items);
while(iterator.hasNext()){
  console.log(iterator.next());
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a65f2b1a-1f63-44b8-aae5-21667c0920c5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3f8f0579-f7c1-4c62-839f-3371e9f3be66&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661670271530&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 제너레이터 이용
const items = [1, &quot;hello&quot;, false, 99.8];

function* Iterator (target) {
  for(item in target) {
    yield item;
  }
}

const iterator = Iterator(items);

for (item of iterator) {
  console.log(item)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;SE-d0b60d4d-85c0-4f16-867c-a0d3763349c4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 5. Template Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-654b8813-48eb-493d-b4d7-92cbcfb3884f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;템플릿 패턴은 객체의 뼈대만 정의. 객체가 만들어지면 세부적인 내용 정의&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eeb32fd7-8a51-4a7d-9d6f-147a4ef3c51e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcLVjm/btrKHwOgJ96/tJAo8d2ESigprhpJkP1sok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcLVjm/btrKHwOgJ96/tJAo8d2ESigprhpJkP1sok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcLVjm/btrKHwOgJ96/tJAo8d2ESigprhpJkP1sok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcLVjm%2FbtrKHwOgJ96%2FtJAo8d2ESigprhpJkP1sok%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;512&quot; height=&quot;298&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c1e5300d-aa32-49f1-b655-a3d5f2c42893&quot;&gt;
&lt;pre id=&quot;code_1661670288531&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 인터페이스 클래스
// 사용자가 구현할 항목 명시
class DataStore {
  connect() {}

  select() {}

  disconnect() {}
}

class Mysql extends DataStore {
  constructor () {
    super()
  }

  process() {
    this.connect();
    this.select();
    this.disconnect();
  }
}

const mySql = new Mysql();

// 상속받은 인터페이스 정의
mySql.connect = function() {
  console.log(&quot;MySQL: connect step&quot;);
};

mySql.select = function() {
  console.log(&quot;MySQL: select step&quot;);
};

mySql.disconnect = function() {
  console.log(&quot;MySQL: disconnect step&quot;);
};

mySql.process();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eb316d17-6dc1-4489-8c11-152a035485b9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7951f95d-45d3-4ade-a798-bd7b9fc2e576&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;템플릿 패턴은 특정 기능을 제공하기 위해 구현할 기능 인터페이스를 제공함으로써 사용자가 원하는 기능을 구현할 수 있도록 도와줌 &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-685f8e3f-1d11-49f5-a7dd-0de59703d65a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d43c1396-050a-40a3-b53f-263685858c2a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;process() 메서드 호출시 수행하는 메소드들을 객체 생성 후 정의한대로 동작&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c2cc38b8-2a61-4217-a83e-eed3819d5871&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-a28317ee-97b5-40ed-87e1-464c928f4b32&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 6. Strategy Pattern&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-7df2b060-a625-40f7-8464-5d3440ee9ec7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Strategy 패턴은 A, B에 대한 알고리즘 정의후 각 알고리즘을 캡슐화하여 런타임 환경에서 각 알고리즘 상호교환&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e2d54c01-4b09-4724-b372-2da0e8b5232c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjlz3o/btrKHaq5H0a/J5o35AM3qHDw9NeO0z7EiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjlz3o/btrKHaq5H0a/J5o35AM3qHDw9NeO0z7EiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjlz3o/btrKHaq5H0a/J5o35AM3qHDw9NeO0z7EiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbjlz3o%2FbtrKHaq5H0a%2FJ5o35AM3qHDw9NeO0z7EiK%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;256&quot; height=&quot;160&quot; data-origin-width=&quot;256&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-44540514-2ab5-4896-8009-2960458ee2fc&quot;&gt;
&lt;pre id=&quot;code_1661670302435&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 전략1 
class FedEx {
  constructor () {}
  calculate(p) {
    return 'FedEx'
  }

}

// 전략2
class UPS {
  constructor () {}
  calculate (p) {
    return 'UPS'
  }
}

// 전략3
class USPS {
  constructor () {}
  calculate (p) {
    return 'USPS'
  }
}

// 전략관리 클래스
class Strategy {
  constructor () {
    this.company = null
  }

  setStrategy (company) {
    this.company = company;
  }

  calculate (p) {
    console.log('this.company')
    if (!this.company) {return}
    return this.company.calculate(p);
  }
}

// 사용
const fedex = new FedEx();
const ups = new UPS();
const usps = new USPS();

const p = { from: 'Alabama',to:'Georgia',weight:1.5};

const strategy = new Strategy();
strategy.setStrategy(fedex); // 런타임 환경에서 ups, usps를 전달할 수 있음
console.log(`Fedex: ${strategy.calculate(p)}`);  // Fedex: FedEx&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-47aa735b-7612-41fd-8fd4-d5e0f10f2ab4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-b6180374-9597-4907-ae39-c3007e79e18d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Visitor Pattern (방문자 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-de18a2ba-c0f5-4e55-a5c2-b1c010852dbe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;방문자 패턴은 방문자(데이터 구조)와 방문 공간(데이터 연산)을 분리. 방문자는 방문 공간으로부터 행동을 위임받아 수행&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-733b50ad-b0c4-483d-92e3-b7d7c8de3778&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;새로운 연산을 추가할 땐 위해 새로운 방문자 추가&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-63c29745-317e-4f53-ada3-cedc6c76d9d5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SSqjV/btrKHYDJHG9/NqMbXhgteKttZgHdCPKtdk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SSqjV/btrKHYDJHG9/NqMbXhgteKttZgHdCPKtdk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SSqjV/btrKHYDJHG9/NqMbXhgteKttZgHdCPKtdk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSSqjV%2FbtrKHYDJHG9%2FNqMbXhgteKttZgHdCPKtdk%2Fimg.jpg&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;560&quot; height=&quot;413&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a643a7b-8031-488e-ba02-cfcc7478bbd5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7ab9883d-a398-43e7-83f8-16dec338def8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저, 방문공간을 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3917bcb8-e565-42ea-ba15-21c379fd2cc7&quot;&gt;
&lt;pre id=&quot;code_1661670325500&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface ComputerPart {
  accept(computerPartVisitor: ComputerPartVisitor): void;
}


class Keyboard implements ComputerPart {
  accept( computerPartVisitor: ComputerPartVisitor) {
     computerPartVisitor.visit(this);
  }
}
class Monitor implements ComputerPart {
  accept( computerPartVisitor: ComputerPartVisitor) {
     computerPartVisitor.visit(this);
  }
}
class Mouse implements ComputerPart {
  accept( computerPartVisitor: ComputerPartVisitor) {
     computerPartVisitor.visit(this);
  }
}
class Computer implements ComputerPart {
  parts: ComputerPart[];
  constructor() {
    this.parts = [new Mouse(), new Monitor(), new Keyboard()]
  }

  accept(computerPartVisitor: ComputerPartVisitor) {
    for (let i = 0; i &amp;lt; this.parts.length; i++) {
      this.parts[i].accept(computerPartVisitor);
   }
    computerPartVisitor.visit(this);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-db47da01-7b89-45fc-8d5f-978d3af3ddb4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9b29587e-521a-4f04-aa5f-a7ca3beff87f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;방문자 패턴을 위한 방문 공간(ComputerPart)정의를 완료했습니다. 해당 공간을 방문할 방문 (ComputerPartVisitor)를 정의하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5e55af56-ea48-4777-9cec-780e7a08cdb7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8dee4c90-d3c0-4661-83f5-f14e54d9a305&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;방문공간은 accept(방문자) 메소드를 통해 방문자를 받는다&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5a2b66a0-2b76-41bd-bda5-32010919883f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1d6d70f8-186e-435e-b491-1fcb9704e746&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음으로 방문공간에 방문할 방문자를 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f7b26240-1809-4fdf-a82c-a8a47db7402a&quot;&gt;
&lt;pre id=&quot;code_1661670336541&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface ComputerPartVisitor {
	visit(computer: Computer);
	visit(mouse: Mouse);
	visit(keyboard: Keyboard);
	visit(monitor: Monitor);
}

class ComputerPartDisplayVisitor implements ComputerPartVisitor {

  visit(computer: Computer): void  {
     console.log(&quot;Displaying Computer.&quot;);
  }

  visit(mouse: Mouse): void  {
     console.log(&quot;Displaying Mouse.&quot;);
  }

  visit(keyboard: Keyboard): void  {
     console.log(&quot;Displaying Keyboard.&quot;);
  }

  visit(monitor: Monitor): void  {
     console.log(&quot;Displaying Monitor.&quot;);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b9755ae6-e6b1-4032-a5b7-48b1e3b8efa8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-12f35b4c-79fe-4fb6-ad70-c5a9c7a9374e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이와같이 동일한 메소드 이름과 다른 파라미터를 통해 메소드를 구성하는 방법을 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;오버로딩&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이라고 부릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c1215148-dd6c-4331-a2f6-5d4bf0615b37&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JavaScript, TypeScript는 오버로딩 지원하지 않습니다&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-db2b163f-5050-4983-b818-288a545424ea&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cb3c566b-43d5-442f-b970-ea676ea5f489&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음과 같이 대체하여 구현합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6ee2fe49-f400-4438-935b-4a3a1fbfe06b&quot;&gt;
&lt;pre id=&quot;code_1661670346405&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ComputerPartDisplayVisitor implements ComputerPartVisitor {
  visit(monitor: Computer | Mouse | Keyboard | Monitor): void {
    if (monitor instanceof Computer) {
      console.log(&quot;Displaying Computer.&quot;);
    } else if (monitor instanceof Mouse) {
      console.log(&quot;Displaying Mouse.&quot;);
    } else if (monitor instanceof Keyboard) {
      console.log(&quot;Displaying Keyboard.&quot;);
    } else if (monitor instanceof Monitor) {
      console.log(&quot;Displaying Monitor.&quot;);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-595250b5-3f8f-420b-b613-e7a5c4b01bd6&quot;&gt;
&lt;pre id=&quot;code_1661670357309&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let computer: ComputerPart = new Computer();
computer.accept(new ComputerPartDisplayVisitor());

/*
실행결과
Displaying Mouse.
Displaying Monitor.
Displaying Keyboard.
Displaying Computer.
*/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6522b51f-86dc-4b36-9676-1a78988f50f2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-84d6736f-8902-4b80-82d4-de03f1b66ee1&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; State Pattern (상태패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a9e855e1-7f63-4033-99da-19aa0c24c5f8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;상태패턴은 상태에 따라 다른 동작을 해야하는 경우 상태 객체를 통해 행동함&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-23ce0458-593a-48cd-83cc-ec9d9e131062&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9ed75a4b-839d-452e-af47-98a584024095&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;상태에 따른 액션을 추가할 때 상태 객체를 추가하여 메인 객체가 해당 상태 객체를 가지고 있는다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a87802c0-c9dc-4602-bb01-c3ebc53b5eda&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bruX8P/btrKHxsQ7lD/BpXws3gyLMacIcsdbTlaRk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bruX8P/btrKHxsQ7lD/BpXws3gyLMacIcsdbTlaRk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bruX8P/btrKHxsQ7lD/BpXws3gyLMacIcsdbTlaRk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbruX8P%2FbtrKHxsQ7lD%2FBpXws3gyLMacIcsdbTlaRk%2Fimg.jpg&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;560&quot; height=&quot;413&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9ee97170-6eb7-452b-9620-174458381a2b&quot;&gt;
&lt;pre id=&quot;code_1661670396495&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface StateInterface {
  on(light: Light): void;
  off(light: Light): void;
}

class OnState implements StateInterface {
  stateName: string;

  constructor() {
    this.stateName = 'ON'
  }
  
  getInstance () { 
    return factory.ON
  }

  on (light) {
    light.setState(factory.ON.getInstance())
    console.log('... 동작하지 않음')
  }

  off (light) {
    light.setState(factory.OFF.getInstance())
    console.log('전원 off')
  }
}

class OffState implements StateInterface{
  stateName: string;
  
  constructor() {
    this.stateName = 'OFF'
  }
  
  getInstance () {
    return factory.OFF
  }

  on (light) {
    light.setState(factory.ON.getInstance())
    console.log('전원 on')
  }

  off (light) {
    light.setState(factory.OFF.getInstance())
    console.log('... 동작하지 않음')
  }
}

type State = OnState | OffState;

let factory = {
  ON: new OnState(),
  OFF: new OffState()
}

class Light {
  state: State;

  constructor () {
    this.state = factory.ON.getInstance()
  }

  showState() {
    console.log(`current state: ${this.state.stateName} \n`)
  }

  setState (state: State) {
    this.state = state
  }

  onButtonPress () {
    this.state.on(this)
  }

  offButtonPress () {
    this.state.off(this)
  }
}

let l = new Light()
l.showState()

l.onButtonPress()
l.showState()

l.offButtonPress()
l.showState()

l.offButtonPress()
l.showState()

l.onButtonPress()
l.showState()

l.onButtonPress()
l.showState()

l.onButtonPress()
l.showState()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7c5a80fd-0af1-4d8d-88bd-949549d411ae&quot;&gt;
&lt;pre id=&quot;code_1661670406358&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;current state: ON 

... 동작하지 않음
current state: ON 

전원 off
current state: OFF 

... 동작하지 않음
current state: OFF 

전원 on
current state: ON 

... 동작하지 않음
current state: ON 

... 동작하지 않음
current state: ON&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6bff2d47-688b-42d9-914e-61d293fac836&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-dc9069c3-4991-43c2-8c49-9a93212209ee&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 9. Memento Pattern (메멘토 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-7dc35e19-738d-43aa-8c13-6dbafba00763&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메멘토 패턴은 객체의 상태를 이전으로 돌리기 위해 사용&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-168bee03-6e51-4aa7-90fc-37fe9d4501d9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLIOng/btrKHUH2JOV/1PUu9KemTKzo5KxOvSfTv0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLIOng/btrKHUH2JOV/1PUu9KemTKzo5KxOvSfTv0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLIOng/btrKHUH2JOV/1PUu9KemTKzo5KxOvSfTv0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLIOng%2FbtrKHUH2JOV%2F1PUu9KemTKzo5KxOvSfTv0%2Fimg.jpg&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;560&quot; height=&quot;360&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f165cd7a-f6c5-433f-ab07-e29febbfdfdf&quot;&gt;
&lt;pre id=&quot;code_1661670422887&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Memento {
  state: string = '';

  constructor(state: string){
    this.state = state;
  }

  getState(): string{
  return this.state;
  }	
}

class Originator {
  state: string;

  setState(state: string): void {
    this.state = state;
  }

  getState(): string {
    return this.state;
  }

  saveStateToMemento(): Memento {
    return new Memento(this.state);
  }

  getStateFromMemento(memento: Memento): void {
    this.state = memento.getState();
  }
}

// 상태 복원 객체
class CareTaker {
  mementos: Memento[] = [];

  constructor() { }
  
  add(state: Memento): void {
    this.mementos.push(state);
  }

  get(idx: number): Memento {
    return this.mementos[idx];
  }
}

const originator: Originator = new Originator();
const careTaker: CareTaker = new CareTaker();

originator.setState(&quot;상태 #1&quot;);
originator.setState(&quot;상태 #2&quot;);
careTaker.add(originator.saveStateToMemento());
originator.setState(&quot;상태 #3&quot;);
careTaker.add(originator.saveStateToMemento());
originator.setState(&quot;상태 #4&quot;);

console.log(&quot;현재상태: &quot; + originator.getState());

originator.getStateFromMemento(careTaker.get(0));
console.log(&quot;저장한 0번째 상태: &quot; + originator.getState());

originator.getStateFromMemento(careTaker.get(1));
console.log(&quot;저장한 1번째 상태: &quot; + originator.getState());

/*
실행결과

현재상태: State #4
0번째 상태: State #2
1번째 상태: State #3
*/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1d4f0185-6a0d-4301-b5d0-5fb6b642289c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-c9b17571-cd4f-40a2-82b9-1b39dcfb383e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 10. Mediator Pattern (중재자 패턴)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-62417d86-108b-4ac6-a972-f8f10fa972ac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;중재자 패턴은 이벤트를 처리하는 시스템에서 복잡한 송, 수신자들의 관계를 중재자 객체를 통해 정리하는 패턴&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a0fe7a3e-0d37-4d66-a4fb-a810ff6b8855&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9925052e-881b-4c56-a51f-1ce51835141c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;복잡한 관계를 단순하게 정리하는 역할&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-72b6fc77-32a5-48b5-970c-c493f4009aaf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C6iOG/btrKHYX0juL/P2T5fhPM3znzoxGYKI4VV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C6iOG/btrKHYX0juL/P2T5fhPM3znzoxGYKI4VV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C6iOG/btrKHYX0juL/P2T5fhPM3znzoxGYKI4VV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC6iOG%2FbtrKHYX0juL%2FP2T5fhPM3znzoxGYKI4VV1%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;683&quot; height=&quot;214&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c71a0b9c-6098-42c7-8027-c18505d5bd2c&quot;&gt;
&lt;pre id=&quot;code_1661670452608&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface ISource {
  setMediator(mediator: Mediator): void;
  eventOccured(event: String): void;
}
class TcpComm implements ISource {
  mediator: Mediator;

  setMediator(mediator: Mediator) { // 중재자 설정
    this.mediator = mediator;
  }

  eventOccured(event: String) { // 이벤트의 전달
    this.mediator.onEvent(&quot;TCP comm&quot;, event);
  }
}
class SystemSignal implements ISource {
  mediator: Mediator;

  setMediator(mediator: Mediator) { // 중재자 설정
    this.mediator = mediator;
  }

  eventOccured(event: String) { // 이벤트의 전달
    this.mediator.onEvent(&quot;System&quot;, event);
  }
}


interface IDestination {
  receiveEvent(from: String, event: String): void;
}
class Display implements IDestination {
  receiveEvent(from: String, event: String) {
    console.log(&quot;Display : from &quot; + from + &quot; event : &quot; + event);
  }
}
class Log implements IDestination {
  receiveEvent(from: String, event: String) {
    console.log(&quot;Log : from &quot; + from + &quot; event : &quot; + event);
  }
}

// 등록된 목적지에게 이벤트를 전달하는 역할수행
class Mediator {
  list: IDestination[] = [];

  addDestination(destination: IDestination) {
    this.list.push(destination);
  }

  onEvent(from: String, event: String) {
    this.list.forEach((item: IDestination) =&amp;gt; {
      item.receiveEvent(from, event);
    })
  }
}

const mediator: Mediator = new Mediator();

const tcp: ISource = new TcpComm();
tcp.setMediator(mediator);

const system: ISource = new SystemSignal();
system.setMediator(mediator);

mediator.addDestination(new Display());
mediator.addDestination(new Log());

tcp.eventOccured(&quot;connected&quot;);
tcp.eventOccured(&quot;disconnected&quot;);

system.eventOccured(&quot;Process Killed PID: 1932&quot;)

/*
실행결과

Display : from TCP comm event : connected
Log : from TCP comm event : connected
Display : from TCP comm event : disconnected
Log : from TCP comm event : disconnected
Display : from System event : Process Killed PID: 1932
Log : from System event : Process Killed PID: 1932
*/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-852215fa-b69b-482e-aa23-9a7fc7855dfd&quot;&gt;
&lt;p id=&quot;SE-65c391c6-e1f8-469a-a944-b76956827cea&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c7f8d9ea-18eb-46ce-989e-a96ce3d449dd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-331873fe-fdb1-4332-97fb-5df461753f75&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;일부 내용은 해당 자료를 참고했으며, 여기서 제공한 코드를 es6로 변환했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-aa2807d3-5dee-4df8-b59e-18fcbeb165a7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://dev.to/jainrahul/a-comprehensive-guide-to-javascript-design-patterns-2h7d?fbclid=IwAR2BZK2rHLeOyL6OdACy_tnkvwY89HfN8nAftL0l7L0vIoNXBNFQgfxn7RM&quot;&gt;https://dev.to/jainrahul/a-comprehensive-guide-to-javascript-design-patterns-2h7d?fbclid=IwAR2BZK2rHLeOyL6OdACy_tnkvwY89HfN8nAftL0l7L0vIoNXBNFQgfxn7RM&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661670481166&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;A Comprehensive Guide To JavaScript Design Patterns&quot; data-og-description=&quot;Design Pattern is a widely acknowledged concept in the software engineering industry in terms of the...&quot; data-og-host=&quot;dev.to&quot; data-og-source-url=&quot;https://dev.to/jainrahul/a-comprehensive-guide-to-javascript-design-patterns-2h7d?fbclid=IwAR2BZK2rHLeOyL6OdACy_tnkvwY89HfN8nAftL0l7L0vIoNXBNFQgfxn7RM&quot; data-og-url=&quot;https://dev.to/jainrahul/a-comprehensive-guide-to-javascript-design-patterns-2h7d&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/TLFaD/hyPAvXAuRC/sbaMHkLSDv8BRshk4XoKc1/img.jpg?width=1000&amp;amp;height=500&amp;amp;face=0_0_1000_500,https://scrap.kakaocdn.net/dn/7rqzZ/hyPAxVkV4h/XasfNTfOuxCCnmY3sITy6k/img.jpg?width=880&amp;amp;height=724&amp;amp;face=0_0_880_724,https://scrap.kakaocdn.net/dn/dh6Zk8/hyPAqIHKkQ/Osl8G3k5M4dgVMJY5MHJc1/img.jpg?width=880&amp;amp;height=616&amp;amp;face=0_0_880_616&quot;&gt;&lt;a href=&quot;https://dev.to/jainrahul/a-comprehensive-guide-to-javascript-design-patterns-2h7d?fbclid=IwAR2BZK2rHLeOyL6OdACy_tnkvwY89HfN8nAftL0l7L0vIoNXBNFQgfxn7RM&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dev.to/jainrahul/a-comprehensive-guide-to-javascript-design-patterns-2h7d?fbclid=IwAR2BZK2rHLeOyL6OdACy_tnkvwY89HfN8nAftL0l7L0vIoNXBNFQgfxn7RM&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/TLFaD/hyPAvXAuRC/sbaMHkLSDv8BRshk4XoKc1/img.jpg?width=1000&amp;amp;height=500&amp;amp;face=0_0_1000_500,https://scrap.kakaocdn.net/dn/7rqzZ/hyPAxVkV4h/XasfNTfOuxCCnmY3sITy6k/img.jpg?width=880&amp;amp;height=724&amp;amp;face=0_0_880_724,https://scrap.kakaocdn.net/dn/dh6Zk8/hyPAqIHKkQ/Osl8G3k5M4dgVMJY5MHJc1/img.jpg?width=880&amp;amp;height=616&amp;amp;face=0_0_880_616');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;A Comprehensive Guide To JavaScript Design Patterns&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Design Pattern is a widely acknowledged concept in the software engineering industry in terms of the...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dev.to&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8f27c698-d4a7-493d-a9d9-2e09439c5ff3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-12565753-0d71-490e-84c7-7a5122fa85a7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;샘플코드는 따로 깃허브로 제공하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>컴퓨터 공학(Computer Science &amp;amp; Engineering))/디자인 패턴</category>
      <category>Behavioral</category>
      <category>creational</category>
      <category>Design</category>
      <category>pattern</category>
      <category>structural</category>
      <category>구조패턴</category>
      <category>디자인패턴</category>
      <category>생성패턴</category>
      <category>행동패턴</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/97</guid>
      <comments>https://meongae.tistory.com/97#entry97comment</comments>
      <pubDate>Sun, 28 Aug 2022 16:08:21 +0900</pubDate>
    </item>
    <item>
      <title>[암호화] 인코딩, 디코딩, 해시, 암호화, 복호화</title>
      <link>https://meongae.tistory.com/96</link>
      <description>&lt;div id=&quot;SE-a5353d3d-3381-4b52-977d-d04d66a6f156&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f40a947e-bca0-4e13-9605-e6982caa03f2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;언제부턴가 인코딩, 해시, 암호화를 혼용하여 사용하는 나 자신을 발견하게 되었다...&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c5208391-fc0e-4f47-bd6f-d99392791f32&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-565d7e7c-2624-4bd5-80b8-376774877574&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우선 분류부터 해야한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f0a2dbc4-7685-4c3b-860d-84bc82bec7f2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwFsMS/btrKMnJih5J/FKR5C1fyylFNz5KcaVouL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwFsMS/btrKMnJih5J/FKR5C1fyylFNz5KcaVouL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwFsMS/btrKMnJih5J/FKR5C1fyylFNz5KcaVouL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwFsMS%2FbtrKMnJih5J%2FFKR5C1fyylFNz5KcaVouL1%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;640&quot; height=&quot;445&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b59b2418-0f41-4d84-ba17-d305546b0a3a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-289860f3-c646-4044-856d-106e612eae33&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 인코딩 / 디코딩&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-0b2553c6-e9e0-4f1d-b116-175bbbcf445a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인코딩 디코딩은 문자열을 바이트 코드로 바꾸는것을 의미합니다. 대표적으로 base64, url 인코딩이 있습니다. 디코딩은 바이트 코드를 다시 문자열로 복구하는 것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1795980e-848d-4dc2-9d40-589f7332ad70&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-973a06c6-4d62-4f8c-b06f-23670b7c7523&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인/디코딩 대표적인 방식으로는 base64와 url 인코딩이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b3f9f229-f89c-4341-8115-2fb5de9068f9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-605a2829-6413-4283-a339-acce4159f251&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인코딩의 목적은 서로 다른 시스템간 동일한 포맷으로 데이터를 주고받기 위해 사용합니다. 인코딩은 암호화와 완전히 다른 목적을 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e1f7d4c2-a50b-4cf5-a562-7940016a56d7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-e158b2cf-a042-4cfb-8e37-1fd60a2a470b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; base64&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-f595d8af-03a2-4219-824b-a6bbf42d6398&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;base64는 64진법을 의미합니다. Base64는 주어진 문자를 아스키 코드로 변환한 후 2진수로 변환합니다. 그리고 6비트씩 잘라서 나온 값을 base64표를 참고하여 변환한 결과가 base64인코딩 결과입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a9eca3b1-4366-480a-b3b5-fac81349090e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlVTiI/btrKGRSYtQc/zYkSRRnMVr3g7mJH993cHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlVTiI/btrKGRSYtQc/zYkSRRnMVr3g7mJH993cHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlVTiI/btrKGRSYtQc/zYkSRRnMVr3g7mJH993cHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlVTiI%2FbtrKGRSYtQc%2FzYkSRRnMVr3g7mJH993cHk%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;264&quot; height=&quot;518&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-35c77d18-f62b-4e99-9949-100450cc3a96&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;158&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dESpxm/btrKGQzHCwM/wClUVnANnG36ShPBoeU4kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dESpxm/btrKGQzHCwM/wClUVnANnG36ShPBoeU4kk/img.png&quot; data-alt=&quot;출처: 나무위키&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dESpxm/btrKGQzHCwM/wClUVnANnG36ShPBoeU4kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdESpxm%2FbtrKGQzHCwM%2FwClUVnANnG36ShPBoeU4kk%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;582&quot; height=&quot;158&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;158&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 나무위키&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e57fd38b-cbfa-46aa-959b-bd5b5e91e0bb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-44b3b66e-458f-4f19-bf06-7cf223cff54b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Base64 인코딩 결과를 Text content로 돌아가는 과정을 디코딩이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ed96a7b4-a3be-462e-b604-5bf968872205&quot;&gt;
&lt;pre id=&quot;code_1661669306161&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(btoa('Man')) // base64 인코딩
// TWFu

console.log(atob('TWFu')) // base64 디코딩
// Man&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6c8b90eb-8008-4024-9ba4-5419a0bcc47a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6405695d-895b-48fe-85c9-2d82c79d3aed&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;base64는 단순히 텍스트 뿐 아니라 이미지 데이터를 표현하는 방식으로도 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-912c0a5a-d3ab-4796-979e-f84027b4ba3c&quot;&gt;
&lt;pre id=&quot;code_1661669311729&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAYAAABIdFAMAAAA....&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-4ea25a89-46bf-4240-8284-708780fffab5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-61d4167b-36d2-43c2-a13f-c84b339ebd4d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; url 인코딩&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-b28b4245-273a-4388-8434-7c00a68db863&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;url 인코딩은 네트워크 상에서 아스키코드만 해석할 수 있는 환경에서 한글 또는 특수문자 같은 것들을 위해 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0d9fd318-17c3-4dec-b9b2-5dadeb85b6bb&quot;&gt;
&lt;pre id=&quot;code_1661669324705&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;헬로우 WORLD&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-84623a3d-385c-4dea-9201-b81f9a148cc3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-35fcc090-9a15-4174-b411-8ccbc52832bf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기엔 아스키코드로 해석이 안되는 4개의 캐릭터가 있습니다. '헬', '로', '우' 그리고 마지막으로 공백입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-860d19fb-7937-4623-89a3-52763a99bdd8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 텍스트를 url 인코딩하면 다음과 같은 결과를 얻습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bb625af8-95a7-4e32-87f3-22528adb7caf&quot;&gt;
&lt;pre id=&quot;code_1661669330867&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;%ED%97%AC%EB%A1%9C%EC%9A%B0+WORLD&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a379ff80-2b91-426d-90dc-ab29c3025126&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cfae6bde-e6cc-4ca1-b2b4-1aa4db8863a0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자바스크립트에서는 URL 인코딩을 위해 인터페이스를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-adc0c68d-193d-46fb-9af4-9b802115b9a6&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ encodeURI()&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2e467434-caee-4eb6-adce-0a40528883cf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fd149481-f2cf-458d-96a2-fa732b17876e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661669346682&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const url = 'http://www.naver.com/멍개'
console.log(encodeURI(url))

// http://www.naver.com/%EB%A9%8D%EA%B0%9C&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-5635ef04-7383-4854-bdf8-84b0ed391aca&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;encodeURI()는 uri 표현에 사용하는 특수문자인 /, :, ., +, = 는 인코딩하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d939d4f8-33ea-447c-afa6-58d2a684d5e5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661669351938&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;decodeURI('http://www.naver.com/%EB%A9%8D%EA%B0%9C')

// http://www.naver.com/멍개&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5f9eecfc-c06e-423f-a747-2c86e34a5d19&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-4c745659-dbcf-4a5b-8213-913ba29dc020&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ encodeURIComponent()&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dc300309-6665-4b28-8d06-d810e2efcd15&quot;&gt;
&lt;pre id=&quot;code_1661669368626&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const url = 'http://www.naver.com/멍개'
console.log(encodeURIComponent(url))

// http%3A%2F%2Fwww.naver.com%2F%EB%A9%8D%EA%B0%9C&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-60aca108-b6f6-40c8-8ae9-f3e196b46ef7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-71921662-0a99-4ee8-92c6-c48e47f7b59c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;encodeURIComponent는 /, :, +, =와 같이 URI에 표현되는 특수문자도 인코딩합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-58ae8400-d1d5-4085-a3e8-df51d177e5fe&quot;&gt;
&lt;pre id=&quot;code_1661669375859&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;decodeURIComponent('http%3A%2F%2Fwww.naver.com%2F%EB%A9%8D%EA%B0%9C')

// http://www.naver.com/멍개&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-92efebf7-99b0-44ee-84de-15cd4a0e32a0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-db8bf374-1d02-4428-875e-79c40399c7da&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 암호화 / 복호화&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-b6e49430-eddd-4630-abd7-86e7ab3c2d31&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;암호화는 무결성과 기밀성을 유지하기 위해 사용합니다. 암호화는 크게 단방향과 양방향이 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d0695897-62d4-4dfd-8154-6cac7fbc7b16&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b371e0cb-f009-4df9-a23a-6bad15c10c3d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 단방향은 암호화만 되는것을 의미하며 복호화까지 되는것을 양방향이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4a3ccc1e-d333-44a4-afe9-19f462f72fda&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 복호화가 불가능한 단방향 암호화 - 해시&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-8fe9a313-4bfd-4e9d-ab69-4752d80e1711&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;단방향 암호화의 대표적인 방식이 해시입니다. 해시의 특징은 입력 데이터의 크기와 상관없이 항상 같은 크기의 결과를 얻습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-93674a47-2915-4fe5-b53b-97e6ccc37911&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c239a8c1-fdb7-4e2c-a0d5-6ea5ce4e4ff1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;단방향 암호화인 해시를 사용하는 대표적인 예가 블록체인과 JWT 유효성 검사입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7da7b49f-7fe8-4ae0-b6de-d3326c70b2a2&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;233&quot; data-origin-height=&quot;531&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k7z2i/btrKG96LQ9Q/63mpWiBikkQR3ll1crJl0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k7z2i/btrKG96LQ9Q/63mpWiBikkQR3ll1crJl0K/img.png&quot; data-alt=&quot;출처:&amp;amp;nbsp; https://namu.wiki/w/%ED%95%B4%EC%8B%9C&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k7z2i/btrKG96LQ9Q/63mpWiBikkQR3ll1crJl0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk7z2i%2FbtrKG96LQ9Q%2F63mpWiBikkQR3ll1crJl0K%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;233&quot; height=&quot;531&quot; data-origin-width=&quot;233&quot; data-origin-height=&quot;531&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp; https://namu.wiki/w/%ED%95%B4%EC%8B%9C&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fb3fb5bf-c8b7-4e62-be56-f6c54d9d5877&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9b3807d1-4aa1-4205-90d8-079a9c596ed7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nodejs에선 crypto를 이용하여 해시 연산이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7fafa837-9a02-448c-9518-01bad93c7060&quot;&gt;
&lt;pre id=&quot;code_1661669407731&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const crypto = require('crypto');

const createPW = pw =&amp;gt; crypto.createHash('sha512').update(pw).digest('hex')
console.log(createPW('멍개'))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f1aa484e-bdae-4c05-bb20-1b6301ae82e0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-dd56cabb-55d5-4203-80b3-6727ba00b799&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;createHash는 단방향(해시) 알고리즘을 전달합니다,.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7004a4dd-bf1e-421b-a1ba-25c84ec960b5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;update는 암호화할 문자열을 전달합니다.(plain text)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dfc7284e-d0c6-402a-9200-7e771c474f43&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;digest는 출력 결과를 표시할 형식을 지정합니다.(hex는 16진수 형태로 표시하는 것을 의미합니다.)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-88528016-33c5-4c30-a534-47faf2a53f44&quot;&gt;
&lt;pre id=&quot;code_1661669414562&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;7a28c5137e44d896da0f9d3afa2ecd02f9e65a3a54835b4d5605f75362878fa48a23c54c6e60a71b1f355ad33ccbf76dd700582212499ba61c504399e8665b81&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9601192d-8cd7-422c-a2f2-11e03eca9e3c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-45352cec-c84a-485c-91ab-fcf441dee620&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 나온 결과는 복호화가 불가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-deed583a-27a0-4938-ac8c-cb7dd26759cf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6ee0d615-d2d1-4307-82a1-f63827ad3af5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 해시는 해시 충돌이 발생할 수 있어 &lt;/span&gt;&lt;span&gt;&lt;b&gt;pdkdf2(Password-based key derivation function version 2)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 방식인 더 복잡한 방법을 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-75237218-450e-4a76-9d5b-93fa3c3233fb&quot;&gt;
&lt;pre id=&quot;code_1661669422370&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const salt = 'slat 소금 짜당~';
console.log('salt', salt);
crypto.pbkdf2('plain text멍개멍개멍개', salt, 1203947, 64, 'sha512', (err, key) =&amp;gt; {
  console.log('password', key.toString('base64'));
});

// salt slat 소금 짜당~
// password DC7aX5dtmva6TXdjRsdlrtJbE3E1cUzwLgo0OOl0tAwQHFIWgp3Wgzp+zQKEuymItiiQ1w+CilyWrygkHxHSaA==&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3038841e-279e-4982-a1d5-af0f903577d3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e9dd66fb-9173-41be-a236-b3d1f9c324f8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;salt는 plain text를 암호화 할 때 사용하는 키입니다. 해당 키는 절대 외부에 노출하면 안됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6972e91a-cfdc-40f5-af17-7adac24d3671&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-5108371e-453a-44fd-9781-86939edbe2c4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 복호화가 가능한 양방향 암호화&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a7ed9d0f-1b62-4e3a-85d4-b38d6b8f2c8a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;양방향 암호화는 key를 이용하여 암호화를 합니다. 그리고 key를 이용하여 복호화를 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8c236130-8162-4364-830b-644104d05848&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;암호화와 복호화 모두 동일한 키를 사용&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하는 것을 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;대칭키(비밀키) 방식&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이라고 합니다. &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;암호화와 복호화에 다른 키를 이용&lt;/b&gt;&lt;/span&gt;&lt;span&gt;하는 것을 &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;비대칭키(공개키) 방식&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-e78bf5a1-e47b-4a42-b2b7-598125a6a1c0&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 대칭키(비밀키) 방식&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-2821084f-77be-4269-96dd-b3bd4f1a5cb8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대칭키에 대표적인 알고리즘은 2가지로 나뉩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f40adfe4-7433-4003-bed8-5fddf6b3ac38&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;블록 암호 알고리즘: AES, DES, 3DES, SEED, ARIA&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-27a73fe6-bb6f-46b3-9c14-47670acdf2e7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스트림 암호 알고리즘: RC-4&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b011fc9f-dd0d-4069-bf16-ba1077afae63&quot;&gt;
&lt;pre id=&quot;code_1661669448146&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const crypto = require('crypto');

const aesKey = crypto.randomBytes(32) // 32 byte
const iv = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); 

const aes256Encrypt = (text)  =&amp;gt; {
  let cipher = crypto.createCipheriv('aes-256-cbc', aesKey, iv);
  let result = cipher.update(text, 'utf8', 'base64');
  result += cipher.final('base64');
  return result
}

const aes256Decrypt = (cryptogram) =&amp;gt;  {   
  const decipher = crypto.createDecipheriv('aes-256-cbc', aesKey, iv);
  let result = decipher.update(cryptogram, 'base64', 'utf8');
  result += decipher.final('utf8');
  return result
}

let plainTextData = &quot;멍개입니다&quot;
let encryptStr = aes256Encrypt(plainTextData)
let decryptStr = aes256Decrypt(encryptStr)

console.log(&quot;  encrypt : &quot;, encryptStr)
console.log(&quot;  decrypt : &quot;, decryptStr)

//  encrypt :  fXkEV6VmssEaWQddJo+uUA==
//  decrypt :  멍개입니다&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-32788264-1a57-4644-826d-e9a081a23bea&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-9969609a-549c-4b95-b5e2-23736c52ad92&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 비 대칭키(공개키) 방식&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-0b33b5c8-f0cf-4c5a-96f4-af864eb8b605&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비 대칭키 방식은 공개키 방식이라고도 합니다. 비 대칭키 방식은 암/복호화를 위해 한 쌍의 개인키-공개키를 생성합니다. 이때 개인키로 암호화 된 결과는 공개키로만 복호화가 가능하며, 반대도 성립합니다. 단, 공개키로 암호화된 결과는 공개키로 복호화가 불가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6e9ac6a2-a997-4f80-ad27-eb838cc4525d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3fd29b35-987c-4695-8449-ed2f823b2fe6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비대칭키는 두 가지 경우가 있습니다. 개인키로 암호화 하는 경우, 공개키로 암호화 하는 경우&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0899a100-73bf-467a-955a-179766846026&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2d01e39e-49ef-4021-8993-d00ad3b72546&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비대칭키 알고리즘은 크게 두 가지로 나뉩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6e402314-6702-45b0-958a-ebc287be826c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인수분해: RSA&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-75d9847b-56f3-43d8-bcbe-4fb12f58c323&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이산대수: DSA&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a730308f-0aae-4629-a4f9-1970cefe54c5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e99810db-fa2e-470c-a347-60706d3ac446&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;1. 개인키로 암호화 하는 경우 - 전자서명&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7dde94b7-aa6e-49ee-81b5-cb50f9a39882&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;A 유저는 네트워크를 통해 데이터를 전송합니다. 이때 해당 데이터가 A가 전송하게 맞는지를 어떻게 증명할까요? 이때 사용하는 방식이 전자서명 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-87df34d1-2b1b-4cff-a82c-57db408b8a14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eb43a18e-b574-4fcc-a042-75e8829d3141&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;A 유저는 우선 공개키-개인키를 생성합니다. 그리고 개인키로 전송하고자 하는 데이터를 암호화 합니다. 이때 개인키는 절대 노출하면 안됩니다. 그리고 공개키는 외부에 공개를 하여 목적지로 전송합니다. 목적지는 해당 데이터를 전달 받으면 공개된 A 유저의 공개키를 기반으로 복호화 합니다. 정상적으로 복호화가 되었다면 전달받은 데이터가 A 유저가 보낸것을 증명하는 것이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-60058723-639e-493e-90f1-f0125c5473ce&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0b14a9da-5002-4ac3-9b2d-12bf36ad44f9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 만약 해커 H가 A 유저의 개인키가 아닌 다른 개인키를 이용하여 A 유저가 보낸것처럼 위장을 해도 목적지에서는 A 유저의 공개키를 기반으로 복호화를 시도하지만 정상적으로 복호화가 되지 않기 때문에 A 유저가 보낸 데이터가 아닌것으로 간주합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-521f542d-abc3-4b0c-8674-23f2f2263b04&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5562cd89-8687-4a6d-bc7b-dadbc7d20d51&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대표적인 방법이 공인인증서입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4a7f5efc-90ae-4814-8176-bbca19b91d5c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c3b4dc28-d5b1-43ff-a2f7-a1e505ddf423&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;2. 공개키로 암호화 하는 경우 - 인증&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9a1a1dc4-fb97-435f-ace0-146426575cd3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;공개키로 암호화 하는 경우는 다른 사용자가 개인키와 공개키를 가지고 있는 A 유저에게 데이터를 전송할 때 악의적인 유저가 해당 데이터를 감청하더라도 해석할 수 없게 하는 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d3e8f0af-1e2f-461f-93a8-22c89c2b8826&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f104701e-c48f-4228-ba03-9acb456788e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다른 유저가 A에게 데이터를 전송할 때 A가 공개한 공개키를 기반으로 암호화 하여 A에게 전송합니다. 이때 해커 H가 해당 데이터를 감청하더라도 A가 가지고 있는 개인키가 없으면 해당 데이터를 복호화하여 볼 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fd044f92-dce0-4aa9-be35-28006c72decf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fb09afca-31a1-4d29-87bb-b79cdafccf3e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, 해당 방식은 감청이 되더라도 원본 데이터를 볼 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-77d00cb1-0a65-457f-bea8-b9a9745fa37f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c0ceaaa1-ad66-4143-a979-e215b9ef3cea&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;공개키를 암호화 하여 감청이 되더라도 원본 데이터가 유출되는 것을 방지하기 위해 SSL, TLS에서 사용하는 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7148481a-3e80-4afb-bfd5-09abcb420716&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-331ffcc2-d7b0-435c-bc8a-c0f84b744bcf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661669478891&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const crypto = require(&quot;crypto&quot;);

const RSA_PRIVATE_KEY = &quot;-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQC41wsMRbC4M4zkWYPI85WwYttEgbLQmIiHD4g6Kjz43h0+3rgt\n8m6IJtolraHpIus+izEx03kpYgJiTLAdruQBDqXTgTyIafZpLaZxH8kYVTomfjJL\nzqTbxuHz1uLqqOaeLzvKiKbCbbCaKWolgCQOCUu+rj/qdftchEVq/LcCcwIDAQAB\nAoGAbIo6fpZd04zR6zV1YYdIGy+xumS+8Cbh5Q2F3UH4U9t6KPT4CmMV7PWDnCR9\nsz1CDpQF61BXEanv5HFL6eJNGCH20z4SctlnMZCw0CJvel4tue4mVmAORctXfcy8\nA9gXpP2D3+tWInSRjZqDZt95ca6N5htlf99a7dcebh7xQkECQQDl/KChwiHw4nBk\nGuDlRp1G7TdP5chBDccdS0655957ZJCROcrjglfJobaGNFsjhoEyWPMl+Ywbt6IZ\n1FV7Z0FbAkEAzb8rVjhuiUurkf9boO2gq1EBMhNULJJHZOB50dpXiD8LvzWcBzvm\nYPppsMYUNS35ItaqXpvQLYswyIA3Seq2yQJAPen7qHBlyL58+UYPI0oWTyDPUjAO\n8AxwfR9n6z5Ts65ICQCg8QyG654gUBLKMk8ketRdaOy8Xj3aYs+5z4XlnwJABlxE\nkLPJ5wCp2yeTw5PVBbbJXKzwSzhycJHn8i7XyeR5Dn4vxqF5a8ISBl75PPOg4gzU\n03vpoZ7N8UTVcLmK0QJBAN4B3D/iBTce6Q5q3Apza8jzMS5ZZjh4Y8/A9K6IiQ54\nkul2tfIVywHVFoxJzGm4JMkHSf7yoVjsjEDpQvKMnIk=\n-----END RSA PRIVATE KEY-----&quot;
const RSA_PUBLIC_KEY = &quot;-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC41wsMRbC4M4zkWYPI85WwYttE\ngbLQmIiHD4g6Kjz43h0+3rgt8m6IJtolraHpIus+izEx03kpYgJiTLAdruQBDqXT\ngTyIafZpLaZxH8kYVTomfjJLzqTbxuHz1uLqqOaeLzvKiKbCbbCaKWolgCQOCUu+\nrj/qdftchEVq/LcCcwIDAQAB\n-----END PUBLIC KEY-----&quot;

const privateKey = RSA_PRIVATE_KEY.replace(/\\n/g, '\n');
const publicKey = RSA_PUBLIC_KEY.replace(/\\n/g, '\n');

// public key로 암호화
encodeRSAByPublic = (text) =&amp;gt; {
  const buffer = Buffer.from(text);
  const encrypted = crypto.publicEncrypt(publicKey, buffer);
  return encrypted.toString(&quot;hex&quot;);
}

// private key로 암호화
encodeRSAByPrivate = (text) =&amp;gt; {
  const buffer = Buffer.from(text);
  const encrypted = crypto.privateEncrypt(privateKey, buffer);
  return encrypted.toString(&quot;hex&quot;);
}

// private key로 복호화
decodeRSAByPrivate = (text) =&amp;gt; {
  const buffer = Buffer.from(text, &quot;hex&quot;);
  const decrypted = crypto.privateDecrypt(privateKey, buffer);
  return decrypted.toString(&quot;utf8&quot;);
}

// public key로 복호화
decodeRSAByPublic = (text) =&amp;gt; {
  const buffer = Buffer.from(text, &quot;hex&quot;);
  const decrypted = crypto.publicDecrypt(publicKey, buffer);
  return decrypted.toString(&quot;utf8&quot;);
}

const text = '멍개멍개';

console.log('encrypt: public, decript: private')
const encrypted0 = encodeRSAByPublic(text); 
console.log(`encrypted: ${encrypted0}`);

const decrypted0 = decodeRSAByPrivate(encrypted0); 
console.log(`decrypted: ${decrypted0}`);

console.log('==========================')

console.log('encrypt: private, decript: public')
const encrypted1 = encodeRSAByPrivate(text); 
console.log(`encrypted: ${encrypted1}`);

const decrypted1 = decodeRSAByPublic(encrypted1); 
console.log(`decrypted: ${decrypted1}`);
encrypt: public, decript: private
encrypted: 56f23d4a961151759052e633f0a8762f0c918cee5e6ff8bd335e5043c9fb2048caf3f514bfeb2afba76bad2c9955b80e63188ceb68bc9e543aad155ee0997d98f7023ba6953db4093864bfe37975eec63080e77a4ba92a0a1cde5e096a8e14f1f43e62c92ec8fbfb2768f7520085f5637b3a40cb4b9b9f7f643fc1cfde150aff
decrypted: 멍개멍개

==========================

encrypt: private, decript: public
encrypted: 0d5784fa8fe822ef8de6ae484b1797abef6a855100672b31cb22e065f95a313ff26cee581a22f3edb0abccd34e9a3e2229ba083c6b4d6a00bcbfdbe7f6fcfb2dc832ef83a5fb6a14d0e0f4137eed872e88866b26ff44f805c75c86ae5d27a8092dffee1baac12cf40dea777206c8a1e43393e078cb3ba477753b314d620cac03
decrypted: 멍개멍개&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bcba5f4a-6d52-4331-892f-7c73f7087bc1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c122afa6-8c0e-42e5-8154-fc173aed4566&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;암호화: 공개키, 복호화: 개인키&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-315fdea5-0d9b-43b7-b418-6bc1d007b176&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;암호화: 개인키, 복호화: 공개키&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b1cdc815-efbe-428b-aaff-f8ef88d29135&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7dbd3db3-120a-4e8c-9903-151fe1824d21&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2가지 방식 모두 정상적으로 암/복호화를 진행합니다. 만약 암호화와 복호화를 같은키를 이용한다면?&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b2bdbbe9-04dc-4819-b701-ee8f0cd8091d&quot;&gt;
&lt;pre id=&quot;code_1661669487139&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;onsole.log('encrypt: public, decript: public')
const encrypted2 = encodeRSAByPublic(text); 
console.log(`encrypted: ${encrypted2}`);

const decrypted2 = decodeRSAByPublic(encrypted2); 
console.log(`decrypted: ${decrypted2}`);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e44f8a0b-d72d-49f9-94f8-76f2b82867d2&quot;&gt;
&lt;pre id=&quot;code_1661669498459&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node:internal/crypto/cipher:79
    return method(data, format, type, passphrase, buffer, padding, oaepHash,
           ^

Error: error:0407008A:rsa routines:RSA_padding_check_PKCS1_type_1:invalid padding
    at Object.publicDecrypt (node:internal/crypto/cipher:79:12)
    at decodeRSAByPublic (/Users/jeongtaepark/Desktop/encrypt/rsa.js:33:28)
    at Object.&amp;lt;anonymous&amp;gt; (/Users/jeongtaepark/Desktop/encrypt/rsa.js:61:20)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47 {
  opensslErrorStack: [
    'error:04067072:rsa routines:rsa_ossl_public_decrypt:padding check failed'
  ],
  library: 'rsa routines',
  function: 'RSA_padding_check_PKCS1_type_1',
  reason: 'invalid padding',
  code: 'ERR_OSSL_RSA_INVALID_PADDING'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-77c76ab1-1996-4b6d-8278-3d392ed7f43e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-100fdbb9-9eaa-47ba-966e-6b1d4a7448fd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;에러가 발생합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3f2140c5-81b5-4183-b26b-5c3e725c9109&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6f82dec9-987c-4f99-a1e3-fba771d140b8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;공개키 - 개인키는 openssl을 이용하여 생성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7d9022ff-eb67-4a71-85d8-ddc731608ab8&quot;&gt;
&lt;pre id=&quot;code_1661669506276&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ openssl genrsa -out private.key 2048

$ openssl rsa -in private.key -out public.key -pubout&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9e9d9161-1776-4277-8feb-36a7af62c45c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-857ff48b-2a89-4ed0-a4e0-2d9ab51ae0ee&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비대칭키 알고리즘은 대칭키 알고리즘보다 더 많은 연산을 하기 때문에 대칭키보다 연산 결과가 느립니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>보안/암호학</category>
      <category>DECODE</category>
      <category>decrypt</category>
      <category>encode</category>
      <category>ENCRYPT</category>
      <category>HASH</category>
      <category>디코드</category>
      <category>복호화</category>
      <category>암호화</category>
      <category>인코딩</category>
      <category>해시</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/96</guid>
      <comments>https://meongae.tistory.com/96#entry96comment</comments>
      <pubDate>Sun, 28 Aug 2022 15:52:03 +0900</pubDate>
    </item>
    <item>
      <title>[네트워크] TCP 핸드쉐이크... UDP가 그렇게 빨라?</title>
      <link>https://meongae.tistory.com/95</link>
      <description>&lt;div id=&quot;SE-34b605e2-3976-44e3-a6ff-4a23b816a65b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-83695095-8b2c-4f34-bdec-ee6ce4bb6eb3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;안녕하세요. 멍개입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-13b42e47-067f-46b6-a6e7-32ebc8db8c89&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3fb0e547-881a-4f21-ad8f-ab1d23713ed5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지난시간까지 TCP 기반의 대표적인 프로토콜 HTTP, WebSocket, Socket.io, RPC를 알아보았습니다. 여기서 3-way handshake, 4-way handshake라는 용어를 사용했는데 이번 시간에는 TCP에서 데이터 전송 전/후로 커넥션을 생성하고 끊는 과정인 핸드쉐이크를 설명합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-587a8fff-66ad-4d12-93cd-a56466e18bc2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a454668b-8796-49ff-bd29-0784d10146ff&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TCP 프로토콜은 크게 3가지 흐름이 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4532eb25-4668-453d-8725-7503c416fe5f&quot;&gt;
&lt;pre id=&quot;code_1661668367392&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;연결 생성 (Connection establishment)
데이터 전송 (Data transfer)
연결 해제 Connection termination)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-29da5641-826f-49d7-a6fd-a16668eb0e4a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2a0ccfe4-e85d-46af-92b6-54c543f0f94c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;본론으로 들어가기 전에 한 가지 질문을 하겠습니다. TCP가 UDP보다 느린 이유가 무엇일까요?&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-15fac92c-dfe9-44f7-8e55-5f89e426091d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-1d318c46-6bc1-4559-8cb3-b4d06675bd30&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● TCP 패킷구조&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2baecc49-4eed-45b6-b942-7feb428a70bb&quot;&gt;
&lt;pre id=&quot;code_1661668384328&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9f6e881a-f508-4035-911c-45bffce119a2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8c5e6e6a-26cc-484a-87b1-ea87cb02f117&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;(출처: &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc793&quot;&gt;https://datatracker.ietf.org/doc/html/rfc793&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1b57f81a-8af9-4c0c-9c7c-f5a8089240e0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e447ff65-b9bf-4cce-abe1-6b01488e0e86&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 모습은 아마 웹소켓에서 데이터 프레임을 인코딩하고 디코딩할 때 비슷한 형태의 모습을 보았을겁니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3e153b84-c381-48ad-91f3-b358f10f2dfa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-16f0d3ee-9ad0-4394-80d2-8d1c9abcf915&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3-way handshake와 4-way handshake를 할때 사용하는 프레임은 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Seq(Sequence Number)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;b&gt;Ack(Acknowledgment)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;b&gt;SYN&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;b&gt;ACK, FIN&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 입니다. 핸드쉐이크에서 사용하진 않지만 Window는 본인이 사용가능한 버퍼 사이즈를 의미합니다. 여기서 Ack는 숫자를 의미하는 프레임이고, ACK는 플래그를 의미하는 프레임입니다. 이 둘을 혼용하면 안됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-e0e865be-1e43-45c7-89e8-9bdc3cea427a&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Source port (16비트)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-84caf575-cb12-4fee-9d22-d92124a5b91b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출발지 포트번호&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-809c3bc8-c6d7-4336-ad32-02a87fec0b3b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Destination port (16비트)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-cd05e709-7b66-4ada-9353-2024a6c7dea7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;목적지 포트번호&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-cb3380f7-5394-491e-a0fb-e1ccf97c8bee&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Seq(Sequence Number) (32비트)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-2feb67ae-988a-42cb-824b-2e4978e391ea&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Seq는 데이터를 나눠서 전송할 때 해당 패킷이 몇 번째에 해당하는지 의미하는 패킷입니다. 이를 이해하기 위해선 MSS(Max Segment Size)를 이해해야 합니다. 간단하게 설명하면 1000Mb 파일이 존재합니다. 그런데 MSS가 100MB라면 TCP는 해당 데이터를 전송하기 위해 10개의 패킷을 만듭니다. 그리고 각각의 패킷에 Seq를 순차적으로 부여하여 전송하게 됩니다. 수신자는 해당 패킷을 네트워크 상태에 따라 순서대로 받지 못할 수 있지만 Seq는 이를 순서대로 조립할 수 있도록 도와줍니다. 여기서 한 데이터를 여러 패킷으로 쪼갠것을 세그먼트라고 합니다. Seq는 해당 패킷이 몇 번째 세그먼트인지 알려줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-812ab097-86d9-4b59-9eb5-f35da3d0a4eb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;세그먼트는 최대 크기는 MTU로 정해집니다. MTU는 네트워크 정보에서 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3b084ab4-8184-4fc2-ad86-977687ac4716&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blgsmh/btrKLhoXkbb/LbnerxCq9sq6cUgxHroCuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blgsmh/btrKLhoXkbb/LbnerxCq9sq6cUgxHroCuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blgsmh/btrKLhoXkbb/LbnerxCq9sq6cUgxHroCuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fblgsmh%2FbtrKLhoXkbb%2FLbnerxCq9sq6cUgxHroCuK%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;773&quot; height=&quot;380&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-767ac67d-6229-41b8-bb22-693f56f3ed05&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-735003c3-ba2f-44ae-8b66-4f0f684af0a4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최초의 패킷 전송인지 이어서 데이터를 전송하고 있는건지에 대한 SYN에 따라 Seq를 처리하는 방법이 달라집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6ad44049-94be-41fd-a0c2-63a50f315634&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;SYN는 0 또는 1이 될 수 있습니다. 0 또는 1에 따라 Seq가 의미하는 바가 조금은 다릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-ad56b200-e0d4-4864-9988-d10a7615d8d6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; &lt;b&gt;Ack(Acknowledgment) (32비트)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-382421ef-4614-4e16-a639-12c7c932776c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;세그먼트를 전달 받으면 해당 패킷은 다음번째 패킷의 Seq를 포함하고 있습니다. 다음번째 세그먼트의 Seq를 의미하는 것이 Ack 입니다. 다음번째 세그먼트의 Seq이기 때문에 Ack가 설정되는 로직은 Seq + 1 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-f5d8f7c2-2105-4334-94e3-95ceba39058f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; &lt;b&gt;ACK (1비트)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-f67dabd7-476a-4064-822d-a61d94d36919&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Ack는 한 쪽에서 데이터를 보냈을 때 수신자가 Ack 패킷을 전송하여 해당 패킷을 받았다고 알려주는 것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-ddf7184f-9875-41c6-b18d-5d43aba6699d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; SYN (1비트)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-35c95d0c-d7bf-4f68-92a9-acf03d6d19bc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;동기화 시퀀스 번호. 최초의 패킷에만 SYN 비트가 1로 활성화 되어야합니다&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-86e310b1-3aa5-4c7f-b858-2eb73993202d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; FIN (1비트)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-9209a853-ad9c-425d-a1b9-da96d0089e6c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막 패킷을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-768fb06a-2eb6-4778-97e8-059abdccda46&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-6bba6fcc-a2e6-4d23-9302-e802369527de&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 연결생성을 위한 3-way handshake&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-8495efc2-40ba-4741-a43e-1f1726b4158a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3-way handshake란 두 응용프로그램간 데이터 전송을 위해 연결하는 과정을 의미합니다. 3-way인 이유는 연결을 위해 패킷을 3번 주고받기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a36135b5-7806-4f75-b480-69938337972a&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDWjdF/btrKJ44tmeh/Cr8ahEggbZLxhfbeXqmkd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDWjdF/btrKJ44tmeh/Cr8ahEggbZLxhfbeXqmkd1/img.png&quot; data-alt=&quot;출처:&amp;amp;nbsp; https://datatracker.ietf.org/doc/html/rfc793&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDWjdF/btrKJ44tmeh/Cr8ahEggbZLxhfbeXqmkd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDWjdF%2FbtrKJ44tmeh%2FCr8ahEggbZLxhfbeXqmkd1%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;594&quot; height=&quot;727&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;727&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp; https://datatracker.ietf.org/doc/html/rfc793&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8448b527-2c80-438b-895d-6c0024fe084f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6ea092ba-844b-4540-9afc-8e6b3f370c1a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RFC에 정의된 TCP의 전체 상태 이미지인데... 보기 힘들죠? 저도 보기 힘듭니다. 해당 이미지에서 연결된 부분만 정리하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-340ed916-2d41-48fc-9a46-2bf72e2a0dcb&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yXbNI/btrKOiOtHyV/TXMdcITo7nD1IUuEtVakUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yXbNI/btrKOiOtHyV/TXMdcITo7nD1IUuEtVakUk/img.png&quot; data-alt=&quot;출처:&amp;amp;nbsp; https://datatracker.ietf.org/doc/html/rfc793&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yXbNI/btrKOiOtHyV/TXMdcITo7nD1IUuEtVakUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyXbNI%2FbtrKOiOtHyV%2FTXMdcITo7nD1IUuEtVakUk%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;602&quot; height=&quot;220&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp; https://datatracker.ietf.org/doc/html/rfc793&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-24e6bf84-51f5-43f7-8fe9-d085c9503a8c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLjiIz/btrKMGot2Sj/IKzzXZrIeVLPAZKCCEokR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLjiIz/btrKMGot2Sj/IKzzXZrIeVLPAZKCCEokR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLjiIz/btrKMGot2Sj/IKzzXZrIeVLPAZKCCEokR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLjiIz%2FbtrKMGot2Sj%2FIKzzXZrIeVLPAZKCCEokR0%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;550&quot; height=&quot;351&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f9aec178-580f-4abc-a3df-f79a81b58563&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cc4eb437-6972-4475-bcdb-942ab2f4c84e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-09fdab75-c13a-4aae-8d86-4fe1e5e0936e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 첫 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e95fc4d0-a242-445d-a274-42b47de16741&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트는 연결 시도를 위해 서버에게 SYN를 1로 활성화 한 패킷을 전송합니다. 해당 패킷은 Seq만 셋팅됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8c94eaf1-f7a4-4193-8316-4e6eab7db23c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;SYN를 1로 설정한 패킷을 보낸 클라이언트의 네트워크 상태는 SYN/ACK 패킷을 기다리며 SYN_SENT 상태가 됩니다. 이때 서버는 LISTEN 상태여야 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-915e8fee-19f6-4e6a-a149-e728a709a8a6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 두 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-d547cdd5-def2-4a5f-9775-7fd915ca9d8c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;SYN 패킷이 1로 활성화 된 패킷을 받은 서버는 연결 요청 수락을 위해 ACK와 SYN가 1로 활성화 된 패킷을 만들어 클라이언트에게 전달합니다. 해당 패킷은 서버가 초기화 한 Seq를 새로 설정하며 클라이언트가 보낸 Seq를 +1하여 Ack로 설정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3077dbdc-bc72-4f07-b404-65cbe991a152&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 서버는 클라이언트가 ACK가 활성화된 패킷을 전송하기를 기다리며 SYN_RECEIVED 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-e4459258-c351-4e49-8d49-c9d8004f63eb&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 세 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-39da2bc8-dc66-4041-86fb-93dca2fed4ba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버에게 ACK와 SYN가 활성화 된 패킷을 받은 클라이언트는 서버에게 해당 패킷을 잘 받았다고 ACK만 활성화 된 패킷을 전달합니다. 해당 패킷은 서버가 만든 Ack를 Seq로 설정하며 서버가 만든 Seq를 +1하여 Ack에 포함합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b7149009-6d77-48f4-bc05-6a354b497cab&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 패킷은 SYN는 0으로 비활성화 상태가 됩니다. 이때 클라이언트는 서버와 데이터를 주고받을 수 있는 상태인 ESTABLISHED가 되며 서버도 클라이언트에게 ACK 패킷을 전달받으면 ESTABLISHED 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-044c5657-27c9-4d92-8a0f-387faafd51db&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5dba488a-bb52-41b5-9ce6-bbfeed1a0e89&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;패킷에서 Seq와 Ack가 만들어지는 과정은 Seq는 Ack에 의해 생성합니다. Seq는 Ack에 의해 생성되는데 SYN이 1이되는 최초의 패킷의 경우 ACK가 없으므로 Seq를 랜덤한 값으로 생성합니다. Ack는 Seq + 1하여 설정합니다. 만약 Seq가 없다면? Ack는 비워집니다. 3-way handshake 첫 번째 패킷에서 Seq가 랜덤하게 만들어지고 Ack는 비워진 상태로 서버에게 패킷을 전달합니다. 서버는 해당 패킷을 받고 Seq를 +1하여 Ack에 설정하고 전달받은 패킷에 Ack이 없기 때문에 서버는 랜덤한 값으로 Seq를 설정합니다. 두 번째 패킷을 받은 클라이언트는 전달받은 패킷의 Ack를 Seq로 설정하고 Seq +1한 값을 Ack로 만들어 패킷을 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-74b3b531-fdfc-450e-add2-c7532003f26b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c51187d5-12b4-494a-b402-8062f26838a5&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP 서버구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b08957d1-cef3-4cfa-9d12-c8cbf55bbaa7&quot;&gt;
&lt;pre id=&quot;code_1661668501203&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-19ab0e0a-7e9c-4ccb-95a2-0b702092e0d6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-aa608343-1bf4-4f36-bd06-25b5ae0460a5&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP 클라이언트 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e1b6946e-e841-4249-87d5-4d8b76ca48b6&quot;&gt;
&lt;pre id=&quot;code_1661668514636&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// 3 way-handshake
const socket = net.connect({ port: 5000 });&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7fe4d5aa-95db-4c5e-94c8-23de96885dd8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-f12d5104-848f-4a9e-9672-cef48e83852e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 패킷 캡처&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-643fe4f0-74b9-49c6-a39d-d23c6fb674f9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버를 실행한 후 와이어샤크 프로그램을 실행합니다. 그리고 클라이언트를 실행하면 다음과 같이 패킷이 캡처됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ac56c8ea-8189-4363-b632-6351bd36b755&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DjGc4/btrKJ5vBcyQ/dq01C9DY1J2Rte8RlgUAy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DjGc4/btrKJ5vBcyQ/dq01C9DY1J2Rte8RlgUAy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DjGc4/btrKJ5vBcyQ/dq01C9DY1J2Rte8RlgUAy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDjGc4%2FbtrKJ5vBcyQ%2Fdq01C9DY1J2Rte8RlgUAy0%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;773&quot; height=&quot;263&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-319160f0-5596-4764-9a63-3f730bed1f97&quot;&gt;
&lt;pre id=&quot;code_1661668529723&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo tcpdump -i lo0 -vvv -nn port 5000                                                                                                                              
tcpdump: listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes

23:01:55.214330 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 64, bad cksum 0 (-&amp;gt;3cb6)!)
    127.0.0.1.60370 &amp;gt; 127.0.0.1.5000: Flags [S], cksum 0xfe34 (incorrect -&amp;gt; 0x620a), seq 2313595154, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 1648035900 ecr 0,sackOK,eol], length 0

23:01:55.214390 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 64, bad cksum 0 (-&amp;gt;3cb6)!)
    127.0.0.1.5000 &amp;gt; 127.0.0.1.60370: Flags [S.], cksum 0xfe34 (incorrect -&amp;gt; 0x2243), seq 679172691, ack 2313595155, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 273853589 ecr 1648035900,sackOK,eol], length 0

23:01:55.214401 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 52, bad cksum 0 (-&amp;gt;3cc2)!)
    127.0.0.1.60370 &amp;gt; 127.0.0.1.5000: Flags [.], cksum 0xfe28 (incorrect -&amp;gt; 0x834c), seq 1, ack 1, win 6379, options [nop,nop,TS val 1648035900 ecr 273853589], length 0

23:01:55.214409 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 52, bad cksum 0 (-&amp;gt;3cc2)!)
    127.0.0.1.5000 &amp;gt; 127.0.0.1.60370: Flags [.], cksum 0xfe28 (incorrect -&amp;gt; 0x834c), seq 1, ack 1, win 6379, options [nop,nop,TS val 273853589 ecr 1648035900], length 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ba6fab30-1524-4d16-abea-3c426b85da59&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b24c5d8e-84ba-498a-94f8-ad188acb84c8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;엥 3개의 패킷이 아니라 4개의 패킷이 캡처되는데요? 마지막 패킷은 핸드쉐이킹이 완료된 후 버퍼의 크기를 확인하기 위한 통신입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4bf5a7b5-5be3-4a99-b150-2864b966924a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;패킷을 하나씩 살펴보면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d0d7560c-d98a-4e9a-bb07-6fbff22c221f&quot;&gt;
&lt;pre id=&quot;code_1661668538050&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;첫 번째 패킷
 127.0.0.1.60370 &amp;gt; 127.0.0.1.5000: Flags [S], seq 2313595154&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-360eda29-d88f-4737-b631-5442d4b359d7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c541f61b-56d1-451f-aef1-1d52669c9354&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트가 서버로 전달한 패킷입니다. Flags는 S인데 이것은 SYN가 활성화 되었다는 의미입니다. seq는 클라이언트가 랜덤하게 만든값 입니다. 앗! 근데 와이어샤크에선 아마 0이라고 뜰건데 이건 계산의 편의를 위해 offset을 별도로 가지고 있고 Seq를 0으로 표기한겁니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c5df3549-fbfc-4038-a969-56c73b92761b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xMlNW/btrKHbpV8mo/KhNykAFaTuf7bplJbnAVRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xMlNW/btrKHbpV8mo/KhNykAFaTuf7bplJbnAVRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xMlNW/btrKHbpV8mo/KhNykAFaTuf7bplJbnAVRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxMlNW%2FbtrKHbpV8mo%2FKhNykAFaTuf7bplJbnAVRk%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;773&quot; height=&quot;483&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-418cf2c1-9225-42b5-946a-cc01362899b3&quot;&gt;
&lt;pre id=&quot;code_1661668550426&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;두 번째 패킷
 127.0.0.1.5000 &amp;gt; 127.0.0.1.60370: Flags [S.], seq 679172691, ack 2313595155&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c8214ffd-26a4-4520-a1ab-60bb368cd9b3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-38a4634f-d6a9-4b12-a246-7c28a1d948a7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 번째 패킷을 살펴보면 Flags에 S.이라고 되어있는데 .은 ACK을 의미합니다. 첫 번째 패킷에 ack(Ack)가 없으므로 서버가 랜던하게 만든값입니다. ack는 seq +1한 값입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c0e90b83-be36-4d43-8bc8-a7902ee849db&quot;&gt;
&lt;pre id=&quot;code_1661668554148&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;세 번재 패킷
 127.0.0.1.5000 &amp;gt; 127.0.0.1.60370: Flags [.], seq 1, ack 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-933a4ea2-8beb-4bc8-a7e5-ce2d85eac530&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e4533633-7bfb-49ee-bc55-61213c843227&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;tcpdump의 세번째 패킷의 seq라 ack는 좀 신기하게 1, 1로 표시합니다. (tcpdump가 신기하게 3-way handshake 이후엔 seq랑 ack를 와이어샤크처럼 보기 편하라고 알아서 계산해서 표기합니다)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ade56a6d-7911-4cc9-ac79-70236df2cfff&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-063e59ab-2892-4d4d-a4a9-ceb1ed18edf1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;와이어샤크에서의 각 패킷을 살펴보면 다음과 같습니다. 아 참고로 tcpdump랑 서로 다른 요청일때 캡쳐했기 때문에 seq랑 ack가 서로 맞진 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f3e68be0-9140-4b83-ad67-c37b46d8ffc2&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwF2S5/btrKOIfgY8T/kckGmOSQYyENrkOXbJlcWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwF2S5/btrKOIfgY8T/kckGmOSQYyENrkOXbJlcWK/img.png&quot; data-alt=&quot;첫 번째 패킷&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwF2S5/btrKOIfgY8T/kckGmOSQYyENrkOXbJlcWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwF2S5%2FbtrKOIfgY8T%2FkckGmOSQYyENrkOXbJlcWK%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;첫 번째 패킷&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668568891&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;seq: 116187442 (랜덤하게 만든 값)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9b1188c0-6fb7-4466-936b-5031d745c7de&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n1y9O/btrKHb4AtrC/wYx75GKTK9KBK6Dc9ENdUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n1y9O/btrKHb4AtrC/wYx75GKTK9KBK6Dc9ENdUK/img.png&quot; data-alt=&quot;두 번째 패킷&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n1y9O/btrKHb4AtrC/wYx75GKTK9KBK6Dc9ENdUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn1y9O%2FbtrKHb4AtrC%2FwYx75GKTK9KBK6Dc9ENdUK%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;두 번째 패킷&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668582549&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;seq: 46286935 (랜덤하게 만든 값)
ack: 116187443(첫 번째 패킷의 seq인 116187442에서 + 1한 값)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5452a097-15af-49f6-9fdd-3cc77eb475eb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/busCWa/btrKMo2vdZl/tzEKcszR1EYbod6RFGkXZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/busCWa/btrKMo2vdZl/tzEKcszR1EYbod6RFGkXZk/img.png&quot; data-alt=&quot;세 번째 패킷&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/busCWa/btrKMo2vdZl/tzEKcszR1EYbod6RFGkXZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbusCWa%2FbtrKMo2vdZl%2FtzEKcszR1EYbod6RFGkXZk%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;세 번째 패킷&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5f16f10a-2f59-45d8-8c68-56ba3ffdbe3d&quot;&gt;
&lt;pre id=&quot;code_1661668595971&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;seq: 116187443(두 번째 패킷의 ack)
ack: 46286936(en 번째 패킷의 seq인 46286935에서 + 1한 값)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9e7e771b-0adf-4ac9-80e0-59b4fc0c570f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-13d58893-6862-48b0-91d0-5b585852dc9c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;와이어샤크에선 예상대로 seq와 ack이 잘 뜨는 모습을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-838c4962-93d9-41e9-badc-6c195e0718f4&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 연결 해제를 위한 4-way handshake&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-770e77aa-86cb-4ea1-94cd-aec965227054&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4-way handshake란 두 응용프로그램간 연결을 끊는 과정을 의미합니다. 4-way인 이유는 연결을 끊기위해 패킷을 4번 주고받기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3306abaa-4f1d-43e8-86bc-d93c56385a9d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzt0tf/btrKGP8wSN2/tolXlTOfv5orfYoxfKKXqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzt0tf/btrKGP8wSN2/tolXlTOfv5orfYoxfKKXqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzt0tf/btrKGP8wSN2/tolXlTOfv5orfYoxfKKXqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzt0tf%2FbtrKGP8wSN2%2FtolXlTOfv5orfYoxfKKXqk%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;595&quot; height=&quot;321&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4c42077f-cac1-4ca8-9d18-aa558a31845b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d3dffc77-2d7b-4d87-a707-a2fc1b9d3cb4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4 way-handshake는 패킷 방향이 중요합니다. 연결을 끊기를 요청하면 수신자측은 2개의 패킷은 전달합니다. 그 이유가 전송중인 데이터가 있다면 해당 전송을 마무리하기 위해서입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-81eafe69-c5bd-405d-b22c-72a644278ba5&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 첫 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-f555aa54-3205-4b3d-bd42-cd3f6ecdc57d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;연결 끊기를 희망하는 쪽에서 FIN을 1로 설정된 패킷을 전송합니다. 패킷을 전송한 대상은 FIN_WAIT_1 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c0a9a7ca-a57b-40d3-9710-0d43c767b275&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 두 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-25f1217c-8f61-4566-ab3e-710a01437921&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;연결끊기 요청(클라이언트) 패킷을 받은 대상은 해당 패킷의 Seq와 Ack를 기준으로 Seq와 Ack를 설정한 후 ACK 플래그를 활성화하여 연결끊기 요청 패킷을 받았다는 사실을 알려줍니다. 연결끊기를 희망하는 대상은 해당 패킷을 받으면 FIN_WAIT_2 상태가 됩니다. 그리고 플래그의 FIN이 활성화 된 패킷을 받기를 기다립니다. 혹시 서버가 이전에 전송중인 데이터가 있다면 마저 전송을 합니다. &lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-740e7b14-d254-4589-bf9b-54f08da648dc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일반적으로 연결은 클라이언트가 끊기를 요청합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-95109a41-731a-4421-8557-e438adb06749&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-3079c443-4cab-4bcf-9255-fe33740cb9b7&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 세 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-62125fc8-ff38-43f4-b583-e834e1b581a2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버가 더이상 클라이언트에 보낼 데이터가 없다면 플래그의 FIN, ACK을 설정한 패킷을 클라이언트에 보낸 후 LAST_ACK 상태가 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9573d631-de36-4efb-9716-b9ddd4a7bc51&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 번째 패킷과 세 번째 패킷은 하나의 패킷을 대상으로 만들어진 패킷이기 때문에 seq와 ack가 동일합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-eb61b994-fce5-4046-8023-1bafae93ca8e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 네 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-6fef7cc2-b821-4f90-b401-f1b54202ec37&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버로부터 FIN 패킷을 받은 클라이언트는 TIME_WAIT 상태로 바뀝니다. FIN을 받았다는 패킷을 보내기 위해 ACK이 활성화 된 패킷을 서버로 보냅니다. 클라이언트로 부터 ACK을 받은 서버는 해당 소켓이 CLOSED 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8014ca80-5f8c-4af4-adcf-3205dccceee4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이후 시간이 지나면 클라이언트도 소켓을 CLOSED로 변경합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b5b805e2-788b-4f65-b6aa-0bc7ced0bcf3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-a927a3e6-0d96-4025-ba8d-512c8511e0ee&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP 서버 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eac80143-2cb7-44c3-a68f-297f1eb93767&quot;&gt;
&lt;pre id=&quot;code_1661668655637&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f21a6075-541e-4d45-b147-4f44207c5bdd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f9b353df-6083-4cae-92ef-6f18ac1e7a77&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버는 앞에서 구현한것과 동일합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a815884e-c30f-48f0-a42d-d4bed6b44812&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;SE-399bc749-bc9a-4360-a036-c170adb4bd67&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP 클라이언트 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-db126ae6-c1b4-41c0-b283-e3d50313220f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d06a640b-1005-46e0-b641-6d76394856c8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668661957&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// 3 way-handshake
const socket = net.connect({ port: 5000 });

socket.on('connect', function () {
  console.log('connected to server!');
  setTimeout(() =&amp;gt; {
    console.log('try disconnected');
    socket.end();
  }, 4000)
});&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-bac72a9a-abe8-40a0-bc11-be5ac30ed3b1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;connect가 되면 4초후 socket.end()를 호출하여 4-way handshake를 발생시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-f8713465-6fd4-4f92-93d8-65780e78b22a&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 패킷캡처&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-72b1a544-c5f2-48d4-b3b3-d0828519052c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(이번엔 tcpdump와 와이어샤크로 같이 캡처 했습니다....)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-41dc1421-f7a7-4dd4-ac8a-fa7fe1697dbd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cncKQY/btrKJ684tDK/1WUi6zihGzC6rjTdYF3Vh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cncKQY/btrKJ684tDK/1WUi6zihGzC6rjTdYF3Vh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cncKQY/btrKJ684tDK/1WUi6zihGzC6rjTdYF3Vh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcncKQY%2FbtrKJ684tDK%2F1WUi6zihGzC6rjTdYF3Vh1%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c5572d59-f814-4c48-922e-931026e275e6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chak5F/btrKHtRskDF/s0lj63cZ7Kwg80GTPnFVzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chak5F/btrKHtRskDF/s0lj63cZ7Kwg80GTPnFVzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chak5F/btrKHtRskDF/s0lj63cZ7Kwg80GTPnFVzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fchak5F%2FbtrKHtRskDF%2Fs0lj63cZ7Kwg80GTPnFVzk%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;773&quot; height=&quot;179&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-385829bf-a296-44c3-8ce4-656b15839847&quot;&gt;
&lt;pre id=&quot;code_1661668677646&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;23:39:56.895863 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 52, bad cksum 0 (-&amp;gt;3cc2)!)
    127.0.0.1.60697 &amp;gt; 127.0.0.1.5000: Flags [F.], cksum 0xfe28 (incorrect -&amp;gt; 0x0d89), seq 1, ack 1, win 6379, options [nop,nop,TS val 1441315233 ecr 3308819552], length 0
23:39:56.895910 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 52, bad cksum 0 (-&amp;gt;3cc2)!)
    127.0.0.1.5000 &amp;gt; 127.0.0.1.60697: Flags [.], cksum 0xfe28 (incorrect -&amp;gt; 0xfdeb), seq 1, ack 2, win 6379, options [nop,nop,TS val 3308823549 ecr 1441315233], length 0
23:39:56.896161 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 52, bad cksum 0 (-&amp;gt;3cc2)!)
    127.0.0.1.5000 &amp;gt; 127.0.0.1.60697: Flags [F.], cksum 0xfe28 (incorrect -&amp;gt; 0xfdea), seq 1, ack 2, win 6379, options [nop,nop,TS val 3308823549 ecr 1441315233], length 0
23:39:56.896197 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 52, bad cksum 0 (-&amp;gt;3cc2)!)
    127.0.0.1.60697 &amp;gt; 127.0.0.1.5000: Flags [.], cksum 0xfe28 (incorrect -&amp;gt; 0xfdea), seq 2, ack 2, win 6379, options [nop,nop,TS val 1441315233 ecr 3308823549], length 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1048c10b-be92-44aa-9bea-19f6343e1351&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c3ab9272-cd7d-49d4-ba4e-db32a84718f2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각각의 패킷을 살펴보면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b82c4b7d-18b6-42cb-9919-533d515c2ae2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-472708db-581b-49fe-bfb9-57ed49e6a288&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 첫 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-e77f518a-1f83-4af0-af04-2dd72adebe76&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 패킷을 보낸 클라이언트는 FIN_WAIT_1 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c239f767-4e4a-45e5-aae1-6020539b0073&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg5IaK/btrKLgcvXa4/1arxIAW7WJprEkFuJV6QC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg5IaK/btrKLgcvXa4/1arxIAW7WJprEkFuJV6QC0/img.png&quot; data-alt=&quot;와이어샤크 캡처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg5IaK/btrKLgcvXa4/1arxIAW7WJprEkFuJV6QC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg5IaK%2FbtrKLgcvXa4%2F1arxIAW7WJprEkFuJV6QC0%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;와이어샤크 캡처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668692014&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;첫 번째 패킷(TCP 덤프)
  127.0.0.1.60697 &amp;gt; 127.0.0.1.5000: Flags [F.], seq 1, ack 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4d394198-f3fe-490e-8a11-ac6101decac7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c7b4dd08-be6f-4af8-8501-799d4b6638dc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트가 서버에게 플래그 비트인 FIN과 ACK을 1로 설정한 후 seq와 ack을 포함하여 서버로 전송합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-192c54d5-837a-49a8-9ccd-f0c16f8659e9&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 두 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-dd05f130-1c34-4dff-b487-3b99416983c8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버로 부터 두 번째 패킷을 받은 클라이언트는 TIME_WAIT 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-101c183f-b689-4436-a05f-690c8c89b8fe&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blJdEV/btrKHVmEKn5/PHMcRgvYj6gizUJy5OSBEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blJdEV/btrKHVmEKn5/PHMcRgvYj6gizUJy5OSBEK/img.png&quot; data-alt=&quot;와이어샤크 캡처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blJdEV/btrKHVmEKn5/PHMcRgvYj6gizUJy5OSBEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblJdEV%2FbtrKHVmEKn5%2FPHMcRgvYj6gizUJy5OSBEK%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;와이어샤크 캡처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bdaf2479-07b0-4c40-96cc-3e9e57ec4c59&quot;&gt;
&lt;pre id=&quot;code_1661668708166&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;두 번째 패킷(TCP 덤프)
  127.0.0.1.5000 &amp;gt; 127.0.0.1.60697: Flags [.] seq 1, ack 2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-70858642-ef66-4a29-bd60-386d061e7f43&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-747d9d7f-f5d9-45a5-ae1d-202cfda1ccc8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버는 클라이언트에게 첫 번째 패킷을 기준으로 seq와 ack를 셋팅한 후 ACK 플래그를 활성화 하여 클라이언트에게 전달합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-a7e28255-d8ed-4be4-856c-fa5e7bd72f64&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 세 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-c13c3317-d1ba-440c-8120-63c7b4d99276&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;세 번째 패킷을 전달한 서버는 LAST_ACK 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7b974d89-8c34-44bf-8ae7-ee9bf36ae9c7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;세 번째 패킷도 서버가 클라이언트에게 전달하는 과정입니다. 첫 번째 패킷을 받은 상태에서 두 번째 세 번째를 서버가 보내기 때문에 seq, ack는 동일합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-128b8c17-cfd8-470c-b30b-fee72ae2e765&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEqnfo/btrKHc3xG2W/CoP8J8Mb7kosCRtNDoN9wK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEqnfo/btrKHc3xG2W/CoP8J8Mb7kosCRtNDoN9wK/img.png&quot; data-alt=&quot;와이어샤크 캡처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEqnfo/btrKHc3xG2W/CoP8J8Mb7kosCRtNDoN9wK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEqnfo%2FbtrKHc3xG2W%2FCoP8J8Mb7kosCRtNDoN9wK%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;와이어샤크 캡처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2040341a-0aa9-410d-b716-3a5df242ff62&quot;&gt;
&lt;pre id=&quot;code_1661668725575&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;세 번째 패킷(TCP 덤프)
  127.0.0.1.5000 &amp;gt; 127.0.0.1.60697: Flags [F.] seq 1, ack 2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-75eec9fa-b4b8-4f33-93f0-8e7070096f3e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-bcc749fb-64cb-471e-84f4-382e0fbfed65&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 네 번째 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-0a3995db-7bbc-4053-9130-e3749b801360&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버로부터 FIN 패킷을 받은 클라이언트는 TIME_WAIT 상태로 바뀝니다. 클라이언트로 부터 ACK을 받은 서버는 해당 소켓이 CLOSED 상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-64ce5806-a7e5-41b4-a89a-7bc8aafb95c0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이후 시간이 지나면 클라이언트도 소켓을 CLOSED로 변경합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c895df2e-21e8-4d57-b657-fa28cf75f168&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yoPT0/btrKGPOeGHC/92bqDHC5241mvIwYpP20Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yoPT0/btrKGPOeGHC/92bqDHC5241mvIwYpP20Tk/img.png&quot; data-alt=&quot;와이어샤크 캡처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yoPT0/btrKGPOeGHC/92bqDHC5241mvIwYpP20Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyoPT0%2FbtrKGPOeGHC%2F92bqDHC5241mvIwYpP20Tk%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;와이어샤크 캡처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668740552&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;네 번째 패킷(TCP 덤프)
  127.0.0.1.60697 &amp;gt; 127.0.0.1.5000: Flags [.], seq 2, ack 2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-177bebfd-1872-4f90-8b4e-290765ed849c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;SE-92c51c6d-b388-4d34-b904-81cf3db7b822&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 데이터 전송&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-d146ff82-1598-4468-bd60-4989dc216500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리는 TCP 사용을 위해 8개의 패킷을 전송하여 사용하는 모습을 확인했습니다. 만약 데이터 전송을 한다면 클라이언트 또는 서버는 상대방에게 패킷을 전송합니다. 하지만 여기서 끝이 아니라 ACK 플래그를 활성화하여 해당 패킷을 잘 받았다고 알려줘야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ed963730-4937-4862-92e3-972643ff37d8&quot;&gt;
&lt;pre id=&quot;code_1661668754144&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// 3 way-handshake
const socket = net.connect({ port: 5000 });

socket.on('connect', function () {
  console.log('connected to server!');
  setInterval(() =&amp;gt; {
    console.log('send data');
    socket.write('msg');
  }, 4000)
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-194b8743-7d6c-46a3-9eda-5a1755bcd3e3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-41edeb02-46b2-4f7d-b102-3f732f7ff04e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4000ms 마다 한 번씩 서버에게 데이터를 요청하는 코드를 실행 시킨 후 패킷 캡처를 시도해 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dd9573ca-5abc-488c-9941-d9487d1c8f86&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6a9xL/btrKGRSYaoa/Ld1kCnIovSQKlToOXoiH9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6a9xL/btrKGRSYaoa/Ld1kCnIovSQKlToOXoiH9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6a9xL/btrKGRSYaoa/Ld1kCnIovSQKlToOXoiH9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6a9xL%2FbtrKGRSYaoa%2FLd1kCnIovSQKlToOXoiH9k%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;773&quot; height=&quot;577&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2009f223-77c8-4016-b3b4-631775b26a78&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0d4efd73-3baf-4bb5-928a-811c9a25d469&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ACK는 무언가 확인하는 플래그입니다. 잘 전송 받았다고 알립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3dcdb872-b0ec-42e7-a1d7-68fad7586003&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문득 그런생각이 들지 않나요? 그럼 UDP는? 안저런가??&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-27b764f6-ad2b-44a1-83cc-2ced7ded7b01&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-8edc4c44-df09-4ea9-9419-0caaeaf50928&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; UDP 서버&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e9365c6e-0e07-4a6f-b7ba-3b6d6b27707e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-98cd9253-2bcf-4dde-93aa-077c75326c89&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668769321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const port = 5000;
 
server.on('message', (message, info) =&amp;gt; {
  console.log(`message: ${message.toString()}`);
  console.log(`from address: ${info.address} port: ${info.port}`);
});
 
server.on('listening', () =&amp;gt; {
  const address = server.address();
  console.log(`listening ${address.address}:${address.port}`);
});
 
server.bind(port);&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-4fb6f9a2-13f2-4d41-bd3a-63498783d2b6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; UDP 클라이언트&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-65c82c84-e422-43c8-8a99-40ad35c4adea&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-88675bf0-6a6c-4a00-81e8-fda3d99e2155&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668776145&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const dgram = require('dgram');
const toHost = '0.0.0.0';
const toPort = 5000;
const client = dgram.createSocket('udp4');
 
const data = Buffer.from('mung');
 
client.send(data, toPort, toHost, (err) =&amp;gt; {
  if (err) console.log(err);
  else console.log('ok');
  client.close();
});&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-4363a994-4a5c-4a9b-b30d-ca4833a23ab9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 패킷 캡처&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c3bd5035-dc70-497e-8c90-11bdb11f128b&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YylqA/btrKGQsVdR4/X8SI4tgC3mUrIpMkAN6h9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YylqA/btrKGQsVdR4/X8SI4tgC3mUrIpMkAN6h9k/img.png&quot; data-alt=&quot;와이어샤크 캡처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YylqA/btrKGQsVdR4/X8SI4tgC3mUrIpMkAN6h9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYylqA%2FbtrKGQsVdR4%2FX8SI4tgC3mUrIpMkAN6h9k%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;773&quot; height=&quot;357&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;와이어샤크 캡처&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c3898609-25be-4ccc-9334-546f951a604d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-35369d8d-323a-429c-866a-2633f654693c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;와이어샤크는 UDP.port로 UDP 통신만 필터합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5c9408bb-c53a-4524-9f5b-992868c68da2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/df4ryL/btrKHT3sbdt/foTZG0gib0v2y2mW3gq1Qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/df4ryL/btrKHT3sbdt/foTZG0gib0v2y2mW3gq1Qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/df4ryL/btrKHT3sbdt/foTZG0gib0v2y2mW3gq1Qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdf4ryL%2FbtrKHT3sbdt%2FfoTZG0gib0v2y2mW3gq1Qk%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;773&quot; height=&quot;108&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c2945bd3-136c-47dd-8230-f4a4508c4954&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-486bf8ca-ffba-4c97-af43-302de7545047&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하나의 요청에 하나의 패킷만 생성되는 모습을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eef098fa-ee59-4e70-919c-d35c5ef18035&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-af5635fd-2755-46fa-9ec8-7f8b342da7d0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;와이어샤크나 tcpdump 모니터링을 활성화 하고 postman같은 클라이언트 프로그램 또는 http 요청 라이브러리로 요청하는 패킷을 확인해보세요 그럼 12개의 패킷이 캡처되는 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f26e7964-fb30-4649-9574-37e756668b93&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCXR1q/btrKHVNHVX7/46IVn4liLjiNkoJ8FQyZi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCXR1q/btrKHVNHVX7/46IVn4liLjiNkoJ8FQyZi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCXR1q/btrKHVNHVX7/46IVn4liLjiNkoJ8FQyZi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCXR1q%2FbtrKHVNHVX7%2F46IVn4liLjiNkoJ8FQyZi0%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;773&quot; height=&quot;232&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-10ab98be-cb7b-4076-9369-a5e3eeb3d824&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1c96986d-519d-4319-bbf3-ee1feaed3f9c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;왜 http/1.1에서 keep-alive 기능이 나왔는지 아시겠죠?&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ac4e3a4b-971d-4c3b-b107-63ddbb3a2905&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-04302c49-0b23-4f6e-ba80-b6f31c97157a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번시간엔 TCP가 어떻게 연결을 하고 연결 해제를 하는지 알아보았습니다. 다음 시간엔 TCP의 핵심기능인 &lt;/span&gt;&lt;span&gt;&lt;b&gt;흐름제어&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;b&gt;오류제어&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&lt;b&gt;연결제어&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>컴퓨터 공학(Computer Science &amp;amp; Engineering))/네트워크</category>
      <category>3way</category>
      <category>4way</category>
      <category>Handshake</category>
      <category>tcp</category>
      <category>udp</category>
      <category>네트워크</category>
      <category>연결</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/95</guid>
      <comments>https://meongae.tistory.com/95#entry95comment</comments>
      <pubDate>Sun, 28 Aug 2022 15:40:02 +0900</pubDate>
    </item>
    <item>
      <title>[네트워크] 분산된 환경에서의 호출을 위한 RPC, JSON-RPC, gRPC</title>
      <link>https://meongae.tistory.com/94</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 시간은 MSA(Micro Service Architecture)에서 많이 사용하는 프로토콜인 RPC에 대해서 다뤄보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f4c35f49-34ca-4ea0-ada3-0383073976ef&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4504f69f-edfd-4dc7-bfd3-f07dfbda7e49&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;혹시 HTTP를 제대로 이해하고 있지 않다면 다음글을 먼저 읽고 해당 강좌를 보는것을 권장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.28 - [컴퓨터 공학(Computer Science &amp;amp; Engineering))/네트워크] - [네트워크] TCP? HTTP? 그것이 알고싶다&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661667761794&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[네트워크] TCP? HTTP? 그것이 알고싶다&quot; data-og-description=&quot;TCP와 HTTP를 다뤄보도록 하겠습니다. 근데 사실 어렵지 않아요!!!! 이걸 어렵게 설명하니깐 어려운거지..... 어렵지 않은 이유를 알려드릴게요 ​ 사실 어려운 개념은 맞습니다. 왜냐고요? 우리 눈&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/92&quot; data-og-url=&quot;https://meongae.tistory.com/92&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/8LTnj/hyPAvws6cs/meTorHACydzVASPqNQOhM0/img.png?width=296&amp;amp;height=472&amp;amp;face=0_0_296_472,https://scrap.kakaocdn.net/dn/b8Rs26/hyPAAR2J3Q/nmbjIJlzcs24PIEikOlpKK/img.png?width=296&amp;amp;height=472&amp;amp;face=0_0_296_472,https://scrap.kakaocdn.net/dn/bG2QVh/hyPAvQINI4/ZEzTzzh0g1PSJfYbJ2pX01/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/92&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/8LTnj/hyPAvws6cs/meTorHACydzVASPqNQOhM0/img.png?width=296&amp;amp;height=472&amp;amp;face=0_0_296_472,https://scrap.kakaocdn.net/dn/b8Rs26/hyPAAR2J3Q/nmbjIJlzcs24PIEikOlpKK/img.png?width=296&amp;amp;height=472&amp;amp;face=0_0_296_472,https://scrap.kakaocdn.net/dn/bG2QVh/hyPAvQINI4/ZEzTzzh0g1PSJfYbJ2pX01/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[네트워크] TCP? HTTP? 그것이 알고싶다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;TCP와 HTTP를 다뤄보도록 하겠습니다. 근데 사실 어렵지 않아요!!!! 이걸 어렵게 설명하니깐 어려운거지..... 어렵지 않은 이유를 알려드릴게요 ​ 사실 어려운 개념은 맞습니다. 왜냐고요? 우리 눈&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;div id=&quot;SE-ce23b344-7051-4a8b-b0aa-73be06a72b3b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-7547f5d6-adbc-4fa2-be06-605d5885f4d0&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● RPC란?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-90b0b061-7e40-4e79-9d1e-a620cf3e64a0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RPC는 Remote Procedure Call의 약자로 원격 프로시저(함수) 호출을 의미합니다. RPC는 프로세스간 통신을 위한 통신기법 입니다. RPC와 많이 비교하는 것 중 하나가 HTTP 기반의 REST 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7d4fa3c0-0c1b-4977-8a60-98f7a655c8f2&quot;&gt;
&lt;pre id=&quot;code_1661667796022&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RPC vs HTTP

Remote Procedure Call VS Hyper Text Transfer Protocol&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-63f493fd-4cf3-4dad-90e8-2763ba0488c6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a12498e5-f9fa-4c2a-9346-b4ca5c8ea604&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP의 주 목적은 &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;문서의 교환&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;span&gt;입니다. 물론 지금은 문서보다 데이터를 주고받는 형태로 사용되고 있지만, 초기의 HTTP 목적은 HTML 문서를 주고받는 목적으로 설계되었습니다. 반면의 RPC는 무언가 &lt;/span&gt;&lt;span style=&quot;color: #cd8bc0;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;연산을 수행&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;span&gt;하기 위한 목적으로 호출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7434bf5b-b4e6-4acd-b241-0dbfa34da12d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dbbe302e-1a77-49b3-9fd0-26d673df481d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP 요청은 파일명이 a.html인 문서를 주세요&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fb14e3a6-54a9-450c-b161-f714ff301452&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RPC는 a와 b의 값을 연산해주세요&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-98b5d366-0fe7-4377-a24e-c2f06e989da7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0bc6a305-0aed-4c07-a931-eeefa1867ffe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP는 method와 path로 구분하여 정의된 핸들러를 호출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6c605586-6211-4c09-bd55-546c38619b20&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-798148eb-06be-496f-b6cd-17a69b2e09fc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RPC는 프로시저(함수)를 직접호출합니다. 호출하는 코드를 보면 이 정의 부분이 로컬에 있는지 원격에 있는지 구분이 안됩니다. 마치 로컬환경에 정의된 느낌을 받습니다. 이 부분이 RPC의 핵심입니다. RPC의 목적은 프로시저(함수)가 로컬에 있던 원격에 있던 신경쓰지 않습니다. 그리고 프로시저(함수)를 호출하기 때문에 호출하는 대상의 인터페이스가 매우 중요합니다. RPC에서 인터페이스는 매우 중요합니다. 우리가 calculator 함수를 호출할 때 함수 이름과 전달할 파라미터, 응답 데이터의 포맷을 알아야 정상적인 코딩이 가능해지는 것처럼 RPC도 이런 인터페이스가 매우 중요합니다. 오늘날의 RPC는 매우 발전된 형태로써 인터페이스 정의를 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;JSON&lt;/b&gt;&lt;/span&gt;&lt;span&gt;과 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;proto buffer&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 형태로 정의하여 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c643c815-ac8f-49e1-8d5a-fbef6d7c91ba&quot;&gt;
&lt;pre id=&quot;code_1661667803655&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;jsonrpc&quot;: &quot;2.0&quot;, 
  &quot;method&quot;: &quot;test&quot;, 
  &quot;params&quot;: [1,2], 
  &quot;id&quot;: null
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6ee19f50-e58b-431e-9738-62fa175aafe1&quot;&gt;
&lt;pre id=&quot;code_1661667809201&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;syntax = &quot;proto3&quot;;

package com.terry.proto;

message Person{
  string name = 1;
  int32 age=2;
  string email=3;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3288231f-e2ac-44ac-ab6e-094e835e601c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9bc70fc1-4759-4af7-9fc9-47a1a9791f2d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MSA에서 HTTP보다 RPC를 사용 하는 이유가 분산된 환경에서 정의된 서비스들을 마치 로컬에서 호출하는것처럼 사용할 수 있기 때문입니다. 그리고 JSON-RPC나 gRPC의 경우 인터페이스를 정의하기 때문에 해당 인터페이스만 가지고 있다면 호출하기가 편리하다는 장점을 가집니다. 물론 gRPC의 경우 HTTP/2.0을 사용하기 때문에 기존의 HTTP/1.1보다 더 많은 장점을 가지고 있기도 합니다. JSON-RPC는 말이 RPC이지 HTTP 통신과 큰 차이를 느끼긴 힘듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dae9b6c1-ede5-44e3-8b62-1bfd8ec54025&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오늘날의 HTTP는 다양한 프로토콜의 기반이 되는 프로토콜이 되어가고 있습니다. 지난 시간에 배웠던 웹소켓, socket.io들도 HTTP 위에서 동작하는 프로토콜이며, 오늘 다룰 JSON-RPC와 gRPC도 HTTP 위에서 동작하는 프로토콜 입니다. JSON-RPC는 HTTP/1.1에서 동작하며 gRPC는 HTTP/2.0에서 동작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-c2e9ac8b-1186-4468-a57b-ed899e71edf8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP는 단순히 문서를 주고받는 규약이 아니라 프로세스간 통신을 위해 데이터를 주고받는 프로토콜로써 자리를 잡고 있습니다. HTTP를 이용하여 두 프로세스를 연결시킨 후 우리가 정의한 프로토콜을 기반으로 새롭게 동작을 정의합니다. 대표적으로 웹소켓은 HTTP 헤더의 Connection을 Upgrade로 정의함으로써 HTTP로 커넥션을 요청한 후 websocket 프로토콜로 업그레이드 하여 통신을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7ff699ba-8b2f-43ac-bb2b-08a1639ac056&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b8d093f9-d238-4da8-96e6-ff7e6905c503&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RPC는 HTTP보다 먼저 나온 개념입니다. HTTP는 1995년에 0.9, 1996년에 1.0이 발표되었으며 1999년에 1.1이 발표되었습니다. 하지만 RPC는 1980년도에 등장하기 시작했습니다. RPC는 TCP/IP를 기반으로 통신을 하지만 IPC를 위해 Named Pipe를 이용하기도 합니다. Named Pipe는 프로세스간 통신하는 기법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b102397c-6903-4a0c-a7ea-49a260e0ec50&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4b55813c-8319-48af-b9ec-2dbbeaab653b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 함수와 프로시저&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-492e41e4-90bd-4346-bfaa-bd45f9849af8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 함수와 프로시저라는 용어가 나왔습니다. 이후에도 함수와 프로시저 용어는 계속 쓰입니다. 이 둘은 호출해서 무언가를 실행한다는 공통점을 가집니다. 하지만 어떤 관점의 실행이냐에 따라 함수 또는 프로시저로 나뉩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5639a478-5879-4b0c-8695-aacb94ee5f05&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a7bc1e69-c95b-4724-a9c6-2478cb0254e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;함수&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 인풋값에 대해서 아웃풋 값이 발생하는 것을 의미합니다. 즉 &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;리턴&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cb4c6a0d-13f3-4135-b73f-9db1cae1a766&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2e90eb11-b046-4b39-8f52-d84f9ea507d8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #cd8bc0;&quot;&gt;&lt;b&gt;프로시저&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 행위에 집중 합니다. 예를들어 A를 수행하고 B를 수행하고 C를 수행하는 일련의 과정을 프로시저로 정의할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f6945d1c-a906-4bec-8da1-afa9edfaf405&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6425aa06-22ca-413a-95d0-0ad414255a63&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;함수와 프로시저는 데이터베이스에서도 사용합니다. 데이터베이스의 함수와 프로시저에서도 함수는 반환값을 주지만 프로시저는 반환값을 정의할 수 없도록 되어있습니다. 프로시저에서 반환값이 필요할 땐 커서 객체를 넘겨서 처리합니다.&lt;/span&gt;&lt;span&gt;(저도 함수랑 프로시저랑 별 차이점 없이 혼용에서 썼었는데 회사에서 DBA 하시는 분이 알려줬음 ㅋ)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7abc952f-9ee4-4063-817c-54b662a9b986&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-49311375-88ee-4c70-b2de-0f08c96c2f9f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 아키텍처&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-c0bf2868-1409-4672-a63f-c138e62a6893&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RPC의 전체적인 모습은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-44649396-a3bc-44e9-91fa-c768a99ab8a6&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UBrle/btrKK9YONWG/WHFpLPXmAVaZzmLjPaOHC0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UBrle/btrKK9YONWG/WHFpLPXmAVaZzmLjPaOHC0/img.jpg&quot; data-alt=&quot;출처:&amp;amp;nbsp; https://www.ibm.com/docs/en/aix/7.1?topic=call-rpc-model&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UBrle/btrKK9YONWG/WHFpLPXmAVaZzmLjPaOHC0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUBrle%2FbtrKK9YONWG%2FWHFpLPXmAVaZzmLjPaOHC0%2Fimg.jpg&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;545&quot; height=&quot;426&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp; https://www.ibm.com/docs/en/aix/7.1?topic=call-rpc-model&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;RPC는 정의된 인터페이스에 따라 호출을 하면 Stub을 만든 후 통신 가능한 형태로 변환하여 통신을 시도합니다. 그리고 통신 결과를 호출자에게 전달해줍니다. 클라이언트와 서버 사이의 통신은 TCP를 이용하겠죠? TCP를 이용한다는 것은 포트를 이용한다는 의미입니다. JSON-RPC와 gRPC는 Network message를 TCP를 이용한 HTTP로 주고받습니다. RPC는 OSI계층에서 전송계층과 응용계층을 연결하는 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;SE-ba2b8d62-1400-433a-8edf-83a37f200fc0&quot;&gt;
&lt;p id=&quot;SE-b54208c9-dd0c-4f2c-9e80-8c56442ac719&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정리하면 RPC는 인터페이스에 맞춰서 호출을 하면 원격 프로시저 또는 로컬 프로시저가 위치하는 곳으로 호출합니다. 이때 HTTP를 이용하여 호출 대상이 존재하는 목적지 프로세스까지 전달합니다. 호출 대상은 호출한 프로시저 함수를 실행한 후 결과를 돌려줍니다. RPC를 위해 HTTP를 사용한다는 것은 HTTP로도 RPC 호출을 할 수 있다는 것을 의미합니다. RPC 코드를 구현해보면 HTTP 위에 RPC를 추가하여 사용하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-45e6fdf1-eceb-4dc8-b577-ea81a3381d08&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● RPC 구현&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-127e66d5-bf4e-47d0-b9c6-fb1a2fcd631d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nodejs에선 rpc 라이브러리를 이용하여 RPC 서버를 구성하고 클라이언트를 만들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-e444a3b1-df6e-413e-abcb-caef3ab355b6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 의존성 라이브러리 설치&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b33eb92d-fd1d-4490-8777-a4785a35dce9&quot;&gt;
&lt;pre id=&quot;code_1661667864540&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save connect rpc&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8928f54a-5124-4770-b2be-51cbda464889&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f2d18959-4fd6-4802-86eb-6f2239edf258&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;connect는 express와 유사한 HTTP 서버 경량 프레임워크입니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-8a0e8e1d-3257-4c40-940f-8f0e1526c087&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 서버 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-61ec07a6-5b6f-4987-b3f6-d44664e1afa6&quot;&gt;
&lt;pre id=&quot;code_1661667879041&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const app = require('connect')();
const path = require('path');
const RPC = require('rpc');

const url_path = '/api';
const api_path = path.join(__dirname, './rpc-handler');

const rpcServer = RPC(
  url_path, 
  api_path, 
  { cors: true }
)

app.use(rpcServer);

app.listen(5000)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c3c9059b-e2b3-4a86-aa8d-18afc115f053&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-068f8a33-82d7-4bb3-91df-f3ea3f3729e6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;url_path로 엔드포인트 정의를 합니다. rpc 라이브러리는 런타임 엔진이며 실행할 코드를 rpc-handler.js로 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e06049e2-b87d-4bb3-b2f3-7a2c20336d71&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-76635bf4-d233-4a62-a105-3e6ae6d188c2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661667885265&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = function( input, okay, fail ) {
  console.log(input)
	let action = input.action
	if( action == &quot;ping&quot; ) {
		okay( &quot;pong&quot; );
	} else {
		fail( &quot;Unrecognized action: &quot; + action );
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-35a61532-ec87-4898-8b12-9b31bb298c6a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RPC 핸들러는 3개의 인자를 전달받습니다. 첫 번째 인자는 HTTP 요청시 body 데이터를 받으며 okay와 fail은 해당 RPC 요청의 성공응답과 실패응답을 담당하는 함수입니다. &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-d84ce2f5-3e7f-40dd-b667-1c4c6f6f08bc&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 클라이언트 &lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-d2d194ec-fce8-4dd0-a7ca-20b8bdf0143e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RPC 서버를 구축했지만 앞에서도 언급했지만 HTTP 위에서 구현되어 있기 때문에 HTTP 요청을 보내도 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-10e88820-990f-4bb3-8863-c39b0b7ae509&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBE9Vf/btrKHcbi3G3/jQC6lRG6hxxmDhEsoJylnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBE9Vf/btrKHcbi3G3/jQC6lRG6hxxmDhEsoJylnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBE9Vf/btrKHcbi3G3/jQC6lRG6hxxmDhEsoJylnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBE9Vf%2FbtrKHcbi3G3%2FjQC6lRG6hxxmDhEsoJylnK%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;773&quot; height=&quot;608&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-14f90399-cfb4-444c-985f-b4d2584fb3fb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8552c4bd-063a-4fef-bdd5-384e19c4db3f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버에서 action이 ping일 경우 okay를 호출합니다. 만약 action: ping이 아닌 값을 요청하면 fail을 호출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-252326ae-b66f-4950-b1cb-917085f0cb30&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMNF9K/btrKGpvrSb8/wavzWXh5mcLAVNAEqRnyok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMNF9K/btrKGpvrSb8/wavzWXh5mcLAVNAEqRnyok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMNF9K/btrKGpvrSb8/wavzWXh5mcLAVNAEqRnyok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMNF9K%2FbtrKGpvrSb8%2FwavzWXh5mcLAVNAEqRnyok%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;773&quot; height=&quot;608&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-40bf41e4-95e3-41f6-b47e-4da1f0e4e653&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f322f5a6-fc56-49a0-9e44-ec9ca0c69b61&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 이렇게 구현을 하게되면 RPC를 만든 의미가 없습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-78f3aac7-91fc-4843-b237-638904d33330&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-a23a14c2-3979-4acc-8b3f-e21b62523fe0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; RPC 서버구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-c2098a11-f4fa-47e4-8fa3-43b9aa642226&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 RPC를 구현하기 위해선 인터페이스 정의를 한다고 했습니다. 타입스크립트의 힘을 빌리면 언어수준에서 인터페이스 정의를 맡길 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0176e7a2-74da-4330-8fba-6396ad8a9fda&quot;&gt;
&lt;pre id=&quot;code_1661667910108&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save @node-rpc express @types/express @types/node @ co-body axios&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e02fa772-ded0-4639-a6cb-eb13f04fb8ab&quot;&gt;
&lt;pre id=&quot;code_1661667920498&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createServer, RPCFunctions } from &quot;@node-rpc/server&quot;;
import { jsonDeserializer } from &quot;@node-rpc/server/dist/deserializers/jsonDeserializer&quot;;
import { IncomingMessage, ServerResponse } from &quot;http&quot;;
import express from 'express'

export interface IApi {
  add: (a: number, b: number) =&amp;gt; number;
  subtract: (a: number, b: number) =&amp;gt; number;
  toLocaleString: (num: number) =&amp;gt; string;
}

interface IContext {
    lang: string;
}

const api: RPCFunctions&amp;lt;IApi, IContext&amp;gt; = {
    add: (a, b) =&amp;gt; () =&amp;gt; a + b,
    subtract: (a, b) =&amp;gt; () =&amp;gt; a - b,
    toLocaleString: num =&amp;gt; context =&amp;gt; num.toLocaleString(context.lang), 
};

const rpcServer = createServer({
    api,
    deserializer: jsonDeserializer,
});

async function main (req: IncomingMessage, res: ServerResponse) {
    const lang = req.headers[&quot;accept-language&quot;]?.split(&quot;,&quot;)?.[0] || &quot;en&quot;;

    const result = await rpcServer.handleAPIRequest(req, { lang });
    console.log(result);

    res.end(JSON.stringify(result));
};

const app = express()

app.post('/rpc', main)

app.listen(5000);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ba151126-578a-4ef0-b95c-ad2facd7d60c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6fad08ce-3624-441f-8ea1-ff64de2fc1e0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;엔드포인트가 /json으로 들어올 때 RPC 런타임을 동작시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5d874e62-5512-4f82-8676-a6ae18e46017&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 코드가 RPC 런타임을 생성하는 부분입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7631d754-070a-4f98-a54d-e16f8658aad0&quot;&gt;
&lt;pre id=&quot;code_1661667929083&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const rpcServer = createServer({
    api,
    deserializer: jsonDeserializer,
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-157d331b-2630-4c7a-925e-4313a3a2b34b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 코드가 RPC 런타임을 HTTP 위에 바인딩 시키는 작업입니다. 바인딩 되는 path는 /rpc 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661667938755&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function main (req: IncomingMessage, res: ServerResponse) {
    const lang = req.headers[&quot;accept-language&quot;]?.split(&quot;,&quot;)?.[0] || &quot;en&quot;;

    const result = await rpcServer.handleAPIRequest(req, { lang });
    console.log(result);

    res.end(JSON.stringify(result));
};

const app = express()

app.post('/rpc', main)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b1be52dc-cab5-4a7a-bb17-68192a8e3fcc&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;SE-7edf964c-6bfb-4248-9823-9bbb05478cc4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; RPC 클라이언트 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1661667954292&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createFallbackClient } from &quot;@node-rpc/client&quot;;
import { jsonSerializer } from &quot;@node-rpc/client/dist/serializers/jsonSerializer&quot;;
import { axiosXHR } from &quot;@node-rpc/client/dist/xhr/axios&quot;;

interface IApi {
  add: (a: number, b: number) =&amp;gt; number;
  subtract: (a: number, b: number) =&amp;gt; number;
  toLocaleString: (num: number) =&amp;gt; string;
}

const api = createFallbackClient&amp;lt;IApi&amp;gt;({
    endpoint: &quot;http://localhost:5000/rpc&quot;,
    serializer: jsonSerializer,
    xhr: axiosXHR,
});

async function main() {
  const response = await api.createRequest('subtract', 11, 4).call();
  
  switch (response.type) {
      case &quot;fail&quot;: {
          console.log(&quot;error&quot;, response.code, response.error);
          break;
      }
      case &quot;noResponse&quot;: {
          console.log(&quot;no response&quot;);
          break;
      }
      case &quot;success&quot;: {
          console.log(&quot;success&quot;, response.code, response.data);
          break;
      }
  }
}

main()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2add240d-8bec-48d8-a29d-68b3b8e9da27&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4a324b79-4f83-4c97-9398-fe3fb0c4e16b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 코드가 RPC 런타임을 만드는 부분입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-694961bd-bfd0-4737-b42a-b1b0b041e0f3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7a72849c-ed22-4210-8969-642f150881a7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661667962987&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const api = createFallbackClient&amp;lt;IApi&amp;gt;({
    endpoint: &quot;http://localhost:5000/rpc&quot;,
    serializer: jsonSerializer,
    xhr: axiosXHR,
});&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-1f7f4063-4b29-4709-abc3-544defcc0ec6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;xhr은 데이터 통신 시 사용할 라이브러리를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-427017c0-191a-4c15-a561-cacf61a70b7e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자 이제 HTTP 프로토콜을 어떻게 활용하여 데이터를 주고 받는지 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3adb4bf1-bf93-44e4-97a0-d7b1e6f422b5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-25b27d87-4472-4820-a1c6-8cb22cabe470&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP 서버로 요청&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-549e4099-6533-48fc-b32d-7ffcbed1ce26&quot;&gt;
&lt;pre id=&quot;code_1661667975420&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    console.log('====== receive data======='); 
    console.log(data.toString());
    socket.write('test')
    console.log('====== receive data======='); 
  });
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-81e88533-26d5-493d-87e1-34a656fea1c1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5760be1a-f619-47a2-b7b7-b3737654e3db&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 서버로 앞에서 구현한 RPC 클라이언트가 요청을 해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7b07a651-0ba8-48d2-b9a8-c3122e20a932&quot;&gt;
&lt;pre id=&quot;code_1661667984216&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const response = await api.createRequest('subtract', 11, 4).call();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9b242d88-d3f3-4f77-876b-3ac5f2b6fc7e&quot;&gt;
&lt;pre id=&quot;code_1661667989765&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;POST /rpc HTTP/1.1
Accept: application/json, text/plain, */*
Content-Type: application/json
Authorization: 
X-RPC-Procedure: subtract
User-Agent: axios/0.25.0
Content-Length: 6
Host: localhost:5000
Connection: close

[11,4]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c25f9a44-31fd-4a8e-84cd-3258c4dccd7c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d189c1da-055a-416a-972d-15beaf1d8184&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;프로시저(함수) 이름은 X-RPC-procedure로 포함합니다. 프로시저로 전달될 파라미터는 body 영역에 포함합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-bea4249e-72b6-474f-8f38-503e093a2a1b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP 클라이언트로 응답&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-b9c7a1ad-ffc5-4526-a7ec-a61e72484171&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번엔 반대로 앞에서 구현한 RPC 서버를 실행한 후 TCP에서 직접 해당 서버로 요청을 보내보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cff670d1-9b8a-4ed7-a117-8133f63e1c1e&quot;&gt;
&lt;pre id=&quot;code_1661668002165&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// 3 way-handshake
const socket = net.connect({ port: 5000 });

socket.on('connect', function () {
  console.log('connected to server!');
  const msg = [
    'POST /rpc HTTP/1.1',
    'Accept: application/json, text/plain, */*',
    'Content-Type: application/json',
    'Authorization: ',
    'X-RPC-Procedure: subtract',
    'User-Agent: axios/0.25.0',
    'Content-Length: 6',
    'Host: localhost:5000',
    'Connection: close',
    '',
    '[11,4]',
  ].join('\r\n')
  socket.write(msg);
});

// 서버로부터 받은 데이터를 화면에 출력 
socket.on('data', function (chunk) {
  console.log('response')
  console.log(chunk.toString());
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dbef6bc3-cb8e-48a9-aac0-8f0643eb1d52&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4fdfebf2-98b4-47c5-9308-9be419648ca3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트를 실행하면 응답 결과를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-826aa72e-6cee-4848-b30a-d0dc1798b3d1&quot;&gt;
&lt;pre id=&quot;code_1661668012181&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;connected to server!
response
HTTP/1.1 200 OK
X-Powered-By: Express
Date: Sat, 29 Jan 2022 01:39:45 GMT
Connection: close
Content-Length: 1

7&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a1af38af-65cb-4744-988e-2b8756e66413&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-3214e3b3-b51b-40bc-aa7c-e18e9c0febe0&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● JSON-RPC&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-ecb43ed3-fd4e-4bb9-b53a-583775d26abb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;rpc를 통해 원격에 존재하는 프로시저(함수)를 호출할 수 있습니다. 하지만 한가지 문제가 있습니다. javascript처럼 자체적으로 인터페이스를 제공하지 않는 언어라면? 인터페이스 정의를 할 수 없습니다. 그래서 JSON-RPC가 등장합니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ecb8ecfd-6fb7-4b7b-9485-2b3a7128867e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 아키텍처 이미지에서 Interface가 명시되어 있습니다. Interface를 IDL이라고 부릅니다. IDL은 Interface Definition Laguage의 약자이며 인터페이스 정의 언어라는 뜻 입니다. JSON-RPC는 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;IDL&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 JSON을 사용합니다. 여기서 인터페이스란 요청을 위한 정해진 폼을 의미하며 JSON-RPC는 요청시 규격화된 JSON 포맷을 이용합니다. 해당 포맷은 jsonrpc 버전, 호출 메서드 이름, 메서드 파라미터, id를 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a42cbb1d-212c-4229-83ec-0c5ca983451e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c24e9b97-17af-404d-87e4-19a1b7752bcb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668030709&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{&quot;jsonrpc&quot;: &quot;2.0&quot;, &quot;method&quot;: &quot;test&quot;, &quot;params&quot;: [1,2], &quot;id&quot;: null},&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;SE-d59e8469-d151-40f4-aefb-bc071fa22de2&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; JSON-RPC 서버구축&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-c95927f2-d5c0-4fad-8904-a71b887ea583&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nodejs에선 JSON-RPC를 위해 node-json-rpc를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b4cf9d01-ed1b-4911-bcac-ebdf54110ced&quot;&gt;
&lt;pre id=&quot;code_1661668042726&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save node-json-rpc&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3a66caa2-2dee-4478-b992-8633b6f7a9a2&quot;&gt;
&lt;pre id=&quot;code_1661668050758&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const rpc = require('node-json-rpc');
 
const options = {
  port: 5000,
  host: '127.0.0.1',
  path: '/',
  strict: false
};
 
const serv = new rpc.Server(options);
 
serv.addMethod('test', function (params, callback) {
  let error, result;
  console.log(params)
  if (params.length === 2) {
    result = params[0] + params[1];
  } else if (params.length &amp;gt; 2) {
    result = params.reduce( (acc, val) =&amp;gt; acc + val, 0);
  } else {
    error = { code: -32602, message: &quot;Invalid params&quot; };
  }
 
  callback(error, result);
});

serv.start(function (error) {
    if (error) throw error;
    else console.log('Server running ...');
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-83a4d2be-0960-43de-a9a7-056eea85d6e9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e790a071-c10b-4415-b47a-eba45ff1fe6d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JSON-RPC는 요청 시 프로시저 이름, 파라미터의 위치가 정의되어 있기 때문에 어플리케이션 단에서 프로시저 이름이 있는지 없는지 검사하지 않아도 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-277444e7-6b67-4f2a-8606-6b4d2790bd14&quot;&gt;
&lt;pre id=&quot;code_1661668058126&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = function( input, okay, fail ) {
  console.log(input)
	let action = input.action
	if( action == &quot;ping&quot; ) {
		okay( &quot;pong&quot; );
	} else {
		fail( &quot;Unrecognized action: &quot; + action );
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-71eb39dd-9b1b-4f4f-9ba2-6b50384fbfb2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2b3b1d5c-9dd5-4455-9c36-d5dcf0fe2dce&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;SE-aeaec061-01eb-4750-97b8-d426f1016ae3&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; json-rpc 클라이언트&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8fe9b10f-1298-48e6-a80f-a1886938e3f8&quot;&gt;
&lt;pre id=&quot;code_1661668072423&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const rpc = require('node-json-rpc');
 
const options = {
  port: 5000,
  host: '127.0.0.1',
  path: '/',
  strict: false
};
 
const client = new rpc.Client(options);
 
client.call(
  {&quot;jsonrpc&quot;: &quot;2.0&quot;, &quot;method&quot;: &quot;test&quot;, &quot;params&quot;: [1,2], &quot;id&quot;: null},
  (err, res) =&amp;gt; {
    if (err) { console.log(err); }
    else { console.log(res); }
  }
);
 
client.call(
  {&quot;method&quot;: &quot;myMethod&quot;, &quot;params&quot;: [1,2], &quot;id&quot;: 2},
  (err, res) =&amp;gt; {
    if (err) { console.log(err); }
    else { console.log(res); }
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-46275e5c-5806-4b39-acea-f3ad8085c6d5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6343f4ee-6995-4ed6-b627-3253dd920e80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트는 정해진 JSON 포맷에 맞추어 요청하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-10ceec20-f6e5-4469-8d07-435dd1c4fb8b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8d0264d7-2d24-4450-ab1e-3b87dd77a2f1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이또한 마찬가지로 HTTP 위에서 동작하기 때문에 HTTP 요청으로도 정상적으로 동작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-85a58f0d-08d9-401b-bf7a-d3408a9d6e6a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SHXpu/btrKGoXD83O/88wH6834tMd6GNWaqIJRaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SHXpu/btrKGoXD83O/88wH6834tMd6GNWaqIJRaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SHXpu/btrKGoXD83O/88wH6834tMd6GNWaqIJRaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSHXpu%2FbtrKGoXD83O%2F88wH6834tMd6GNWaqIJRaK%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;773&quot; height=&quot;608&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-78024211-ffce-4e02-bf76-583d816ab7d4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e02c3f7a-2ec0-4d56-8fc1-ee8d5164babd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;http 요청 도구인 curl을이용하여 요청도 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8bdf6555-d770-4f23-9c66-fcda728b1616&quot;&gt;
&lt;pre id=&quot;code_1661668085887&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl -d '{&quot;jsonrpc&quot;: &quot;2.0&quot;, &quot;method&quot;: &quot;test&quot;, &quot;params&quot;: [1,2], &quot;id&quot;: null}' 127.0.0.1:5080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0b108463-0bdc-4f87-a4ac-ad270014da0d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-3a8797ee-5e7a-4d29-a9fd-dcaa29ced7f0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 요청/응답 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-3799a063-c07b-4261-ae70-0e866b8028e6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TCP 서버와 클라이언트를 이용하여 HTTP 프로토콜을 어떻게 활용하는지 살펴보면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-69355883-e30e-45ed-b7eb-bc2574e5c35b&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 요청 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f7f4f2a6-128d-4532-9b69-edd3f661374d&quot;&gt;
&lt;pre id=&quot;code_1661668107280&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    console.log('====== receive data======='); 
    console.log(data.toString());
    socket.write('test')
    console.log('====== receive data======='); 
  });
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-225e9eac-1471-4479-b5f4-32528323eb1f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3ceb7aa5-b655-4a24-bc31-ab69d06e7c5d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TCP 서버를 실행한 후 앞에서 구현한 JSON-RPC client를 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bc34cf16-e548-40e2-b04d-decbd0610e6a&quot;&gt;
&lt;pre id=&quot;code_1661668114576&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;POST / HTTP/1.1
host: 127.0.0.1:5000
content-type: application/json
content-length: 58
Connection: close

{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;test&quot;,&quot;params&quot;:[1,2],&quot;id&quot;:null}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-91ba9a72-4f27-40ae-b9eb-2d4130cf70c9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-7e706495-d149-4b4a-83a2-01cf1977db82&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 응답 패킷&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-09b0c95b-6fab-4798-a3dd-3c3a2b5ac602&quot;&gt;
&lt;pre id=&quot;code_1661668126312&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// 3 way-handshake
const socket = net.connect({ port: 5000 });

socket.on('connect', function () {
  console.log('connected to server!');
  const msg = [
    'POST / HTTP/1.1',
    'host: 127.0.0.1:5000',
    'content-type: application/json',
    'content-length: 58',
    'Connection: close',
    '',
    '{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;method&quot;:&quot;test&quot;,&quot;params&quot;:[1,2],&quot;id&quot;:null}',
  ].join('\r\n')
  socket.write(msg);
});

// 서버로부터 받은 데이터를 화면에 출력 
socket.on('data', function (chunk) {
  console.log('response')
  console.log(chunk.toString());
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-de64ce97-55b9-4d44-8ba4-d2fcb4bca5a3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a3d0838a-5f69-452b-8830-b3a2c2b9a488&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JSON-RPC 서버를 실행한 후 TCP 클라이언트를 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-85d04309-000e-45cc-a33f-b4c4f857e9a6&quot;&gt;
&lt;pre id=&quot;code_1661668146617&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HTTP/1.1 200 OK
Date: Sat, 29 Jan 2022 02:01:02 GMT
Connection: close
Content-Length: 12

{&quot;result&quot;:3}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ac715e27-e56b-4141-9f2e-2aa68fdc13d0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1755ef61-8678-4617-b5ed-66edf48d51d7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;jayson을 이용하여도 JSON-RPC 구현이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1be8f3d9-39fb-4532-b3a0-19b1878d16d5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.npmjs.com/package/jayson#example&quot;&gt;https://www.npmjs.com/package/jayson#example&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661668143151&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;jayson&quot; data-og-description=&quot;JSON-RPC 1.0/2.0 compliant server and client. Latest version: 4.0.0, last published: 16 days ago. Start using jayson in your project by running &amp;#96;npm i jayson&amp;#96;. There are 329 other projects in the npm registry using jayson.&quot; data-og-host=&quot;www.npmjs.com&quot; data-og-source-url=&quot;https://www.npmjs.com/package/jayson#example&quot; data-og-url=&quot;https://www.npmjs.com/package/jayson&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/9Hcc8/hyPBSjfFsO/BsZScND4qMaEBjqGyjKpI1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.npmjs.com/package/jayson#example&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.npmjs.com/package/jayson#example&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/9Hcc8/hyPBSjfFsO/BsZScND4qMaEBjqGyjKpI1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;jayson&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;JSON-RPC 1.0/2.0 compliant server and client. Latest version: 4.0.0, last published: 16 days ago. Start using jayson in your project by running `npm i jayson`. There are 329 other projects in the npm registry using jayson.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.npmjs.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1ac51f19-9ea7-42c1-9130-56bc7d9a47a4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;a href=&quot;https://www.npmjs.com/package/jayson#example&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e70eb929-1029-48e3-9ed9-9cafde6e6bad&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-15e4b262-a4ff-41f8-b5e4-7855d3e9c145&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;● gRPC&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-b2910cb0-f4cc-476e-8fde-7a6ba4d170e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;gRPC는 IDL을 프로토 버퍼를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4f10edb9-31cc-49d8-8d17-03d0b3e16ab0&quot;&gt;
&lt;pre id=&quot;code_1661668164426&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;syntax = &quot;proto3&quot;;

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {};
}

message HelloRequest {
  required string name = 1;
}

message HelloReply {
  optional string message = 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-db7352d1-458b-4a69-8823-b08003f641fc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0b0f0d61-5849-4ee3-a42a-9fc2a8c720c1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 HTTP/2.0을 사용합니다. gRPC는 RPC의 프레임워크라고 소개됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e6db409a-65e0-4a73-8f33-e81f99f6e7be&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ9e6G/btrKOh9QWsA/s4PZpyJfcMBukv5TnEDyMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ9e6G/btrKOh9QWsA/s4PZpyJfcMBukv5TnEDyMK/img.png&quot; data-alt=&quot;출처:&amp;amp;nbsp; https://www.grpc.io/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ9e6G/btrKOh9QWsA/s4PZpyJfcMBukv5TnEDyMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ9e6G%2FbtrKOh9QWsA%2Fs4PZpyJfcMBukv5TnEDyMK%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;773&quot; height=&quot;425&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp; https://www.grpc.io/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6c0e3180-9bf2-4afa-9876-0bf7728f2870&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-38f514af-b8b0-405d-8cf8-e1c85027195a&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; gRPC 서버 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d894430a-8ca0-48ef-af46-6acd3f84132b&quot;&gt;
&lt;pre id=&quot;code_1661668180970&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save @grpc/grpc-js @grpc/proto-loader&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3a4b1510-d0d7-482d-a948-f8ca56c7f8db&quot;&gt;
&lt;pre id=&quot;code_1661668189530&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
// Suggested options for similarity to existing grpc.load behavior
const packageDefinition = protoLoader.loadSync(
    './helloworld.proto',
    {keepCase: true,
     longs: String,
     enums: String,
     defaults: true,
     oneofs: true
    });
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
// The protoDescriptor object has the full package hierarchy
const routes = protoDescriptor.helloworld;

function sayHello(call, callback) {
  console.log(call.request)
  callback(null, {message: 'Hello ' + call.request.name});
}

function main(port = '5000') {
  const server = new grpc.Server();
  server.addService(
    routes.Greeter.service, {
      sayHello
    }
  );
  server.bindAsync(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure(), () =&amp;gt; {
    server.start();
  });
}

module.exports = main;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ba5c1c57-cdde-48c5-8f21-f0831d3f60fd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b8975779-b244-4c57-9edd-50776c510258&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;gRPC는 정의된 proto 파일 경로를 명시해야 합니다. gRPC는 런타임은 proto 파일을 기반으로 gRPC 런타임을 동작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-91d1c31c-b5dd-4201-90ae-e9bb62bec124&quot;&gt;
&lt;pre id=&quot;code_1661668195547&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const packageDefinition = protoLoader.loadSync(
    './helloworld.proto',
    {keepCase: true,
     longs: String,
     enums: String,
     defaults: true,
     oneofs: true
    });&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4771ea88-482d-451a-bb47-407916207f2f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-81a0d506-8299-4fdb-852e-b3a6bfa1e7b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;helloworld.proto는 다음과 같이 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a5f25e8d-8d1d-4216-a33c-96d47e069bbd&quot;&gt;
&lt;pre id=&quot;code_1661668202260&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;syntax = &quot;proto3&quot;;

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {};
}

message HelloRequest {
  required string name = 1;
}

message HelloReply {
  optional string message = 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d96d06ed-904d-4c8d-9e92-b7a28b5644c5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-25093eb8-ae96-45ff-85b9-17b2132e1f1f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; gRPC 클라이언트 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-46620a98-f889-45b9-851a-953a2bde8c36&quot;&gt;
&lt;pre id=&quot;code_1661668217564&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const path = require('path');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');

// Suggested options for similarity to existing grpc.load behavior
const packageDefinition = protoLoader.loadSync(
    path.join(__dirname, './helloworld.proto'),
    {keepCase: true,
     longs: String,
     enums: String,
     defaults: true,
     oneofs: true
    });
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
// The protoDescriptor object has the full package hierarchy
const routes = protoDescriptor.helloworld;

function main() {
  var client = new routes.Greeter('localhost:5000',
                                       grpc.credentials.createInsecure());
  client.sayHello({name: 'you'}, function(err, response) {
    console.log('Greeting:', response.message);
  });
}

main()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a01f12b4-7595-4389-91b6-57c7d71aaf9f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8d752460-e7b9-4221-b52a-599b29de3f3b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트도 마찬가지로 정의된 proto를 기반으로 gRPC 런타임을 구성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a6adb3d8-b12d-4df5-81d5-267503fa15e9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-0cede499-b80b-436b-8f2d-d1f98b1629f2&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 요청패킷&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-9776f336-e6ba-4835-9008-955d2287529e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;역시나 TCP를 이용하여 요청/응답 패킷이 어떻게 되는지 확인해보도록 하겠습니다. &lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-fa56efed-a0e5-4ca6-a5aa-40b7b53921f9&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 요청패킷&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-96fb5e6d-ba0f-4df1-b72d-85563eb8c26e&quot;&gt;
&lt;pre id=&quot;code_1661668234572&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    console.log('====== receive data start======='); 
    console.log(data.toString());
    socket.write('test')
    console.log('====== receive data end======='); 
  });
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-37187d07-0f5d-4a40-9e05-e20abacc6fa3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0ae87a7f-131e-424e-8809-cb8aff3a370b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; TCP 서버를 구성 후 gRPC 클라이언트를 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-db67decd-c1a3-4f52-859b-80695cf62430&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-defbb94c-704d-4aa2-8123-01b61462a27e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661668242124&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;====== receive data start=======
PRI * HTTP/2.0

SM

u��br�A��$_�*Kc�h���A����       ��@���Ȱ�B֕�Q!���4��&amp;amp;O��
                                                      -I~��j�P�4��&amp;amp;O�z��&amp;amp;=LMed@te�M�5�b

you
====== receive data end=======
====== receive data start=======
PRI * HTTP/2.0

SM


====== receive data end=======&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-e4e75b3e-1af2-402a-98f5-382dcc416d37&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지난시간에 HTTP/2.0은 하나의 요청인 스트림을 여러 메시지로 분해하여 전송한다고 했습니다. 또한 HTTP/2.0은 암호화(SSL, TSL) 되어 통신을 합니다. TCP 수준에서는 암호화 된 내용을 풀 수 없습니다. 왜냐하면 TCP의 상위레이어에서 암호화를 진행하기 때문에 상위 레이어에서 암호화를 해독할 수 있습니다. 만약 해당 수준에서 암호화가 가능하면 보안상 엄청난 이슈가 발생하게 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e086c401-49e3-4e12-acd4-1e88fbc93878&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/2.0이 HOLB를 해결하기 위해 하나의 요청 스트림을 여러 메시지로 쪼개어 전송된다는 사실을 확인했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2473329e-9700-4636-b03f-4b24f40432c7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ed38e1b1-961c-4c5b-a0f0-83be4aca9f49&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지 TCP부터 HTTP, WebSocket, Socket.io, RPC(RPC, JSON-RPC, gRPC)까지 긴 여정을 오시느라 고생 많으셨습니다. 이 프로토콜은 현재 서비스를 개발할 때 항상 사용하는 프로토콜입니다. 물론 다른 프로토콜들도 있겠지만 4종류의 프로토콜만 잘 이해하고 있다면 다른 프로토콜을 큰 어려움 없이 개발하거나 이해할 수 있을겁니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5ecf6313-dcd6-42d6-8817-e6a19ad14dc4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-77c730fb-c224-4562-8d2a-91e544bb6d10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음번 강의는 TCP의 핸드쉐이크 강의로 찾아뵙겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4ee13ec8-2d1c-4bb6-815c-530c8ad7e1f8&quot;&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;&lt;/div&gt;
&lt;div id=&quot;SE-5143934e-91d1-4a7f-ac5b-0ecd637f4053&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0ed0a35b-18de-4483-a94c-12d12517239c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아 그리고 간혹 블로그 쓸 때 어떤식으로 쓰는지 궁금해하시는 분이 있어서 블로그 쓰기전에 어떤 절차로 쓰는지 간략히 소개를 하면...&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aff817c5-cd9a-4597-add6-188adca696de&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MQth5/btrKJ5I6521/uNUayKh7NBjRJNs7YaliT1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MQth5/btrKJ5I6521/uNUayKh7NBjRJNs7YaliT1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MQth5/btrKJ5I6521/uNUayKh7NBjRJNs7YaliT1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMQth5%2FbtrKJ5I6521%2FuNUayKh7NBjRJNs7YaliT1%2Fimg.jpg&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;773&quot; height=&quot;580&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bd543716-6521-40dc-8b92-7e56186a8cf8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fab719c6-9b34-42dc-868d-cee0d68580cf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;간략하게 정리할 내용을 아주 간략하게만 작성합니다. 개념같은 것들은 구글링 하여 한 3페이정도까지 읽어 본다음에 혹시나 잘못 알고있는 정보나 개념은 없는지 살펴보고 작성을 합니다. 보통 포스팅 시간은 2~3시간정도 걸리는데 이번글은 4시간 정도 걸린것 같습니다 ㅋㅋ&lt;/span&gt;&lt;/p&gt;
&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>컴퓨터 공학(Computer Science &amp;amp; Engineering))/네트워크</category>
      <category>buffer</category>
      <category>json</category>
      <category>proto</category>
      <category>RPC</category>
      <category>tcp</category>
      <category>네트워크</category>
      <category>프로시저</category>
      <category>프로토버퍼</category>
      <category>함수</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/94</guid>
      <comments>https://meongae.tistory.com/94#entry94comment</comments>
      <pubDate>Sun, 28 Aug 2022 15:31:27 +0900</pubDate>
    </item>
    <item>
      <title>[네트워크] TCP와 HTTP 레이어에서 직접 구현하는 웹소켓 그리고 socket.io</title>
      <link>https://meongae.tistory.com/93</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;지난번 글에서 TCP와 HTTP가 무엇인지 그리고 어떻게 동작하는지 살펴보았습니다.&lt;/span&gt;&lt;/p&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;a href=&quot;https://meongae.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.28 - [컴퓨터 공학(Computer Science &amp;amp; Engineering))/네트워크] - [네트워크] TCP? HTTP? 그것이 알고싶다&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661666894825&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[네트워크] TCP? HTTP? 그것이 알고싶다&quot; data-og-description=&quot;TCP와 HTTP를 다뤄보도록 하겠습니다. 근데 사실 어렵지 않아요!!!! 이걸 어렵게 설명하니깐 어려운거지..... 어렵지 않은 이유를 알려드릴게요 ​ 사실 어려운 개념은 맞습니다. 왜냐고요? 우리 눈&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/92&quot; data-og-url=&quot;https://meongae.tistory.com/92&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/8LTnj/hyPAvws6cs/meTorHACydzVASPqNQOhM0/img.png?width=296&amp;amp;height=472&amp;amp;face=0_0_296_472,https://scrap.kakaocdn.net/dn/b8Rs26/hyPAAR2J3Q/nmbjIJlzcs24PIEikOlpKK/img.png?width=296&amp;amp;height=472&amp;amp;face=0_0_296_472,https://scrap.kakaocdn.net/dn/bG2QVh/hyPAvQINI4/ZEzTzzh0g1PSJfYbJ2pX01/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/92&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/92&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/8LTnj/hyPAvws6cs/meTorHACydzVASPqNQOhM0/img.png?width=296&amp;amp;height=472&amp;amp;face=0_0_296_472,https://scrap.kakaocdn.net/dn/b8Rs26/hyPAAR2J3Q/nmbjIJlzcs24PIEikOlpKK/img.png?width=296&amp;amp;height=472&amp;amp;face=0_0_296_472,https://scrap.kakaocdn.net/dn/bG2QVh/hyPAvQINI4/ZEzTzzh0g1PSJfYbJ2pX01/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[네트워크] TCP? HTTP? 그것이 알고싶다&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;TCP와 HTTP를 다뤄보도록 하겠습니다. 근데 사실 어렵지 않아요!!!! 이걸 어렵게 설명하니깐 어려운거지..... 어렵지 않은 이유를 알려드릴게요 ​ 사실 어려운 개념은 맞습니다. 왜냐고요? 우리 눈&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 내용에서 웹소켓은 HTTP 위에서 동작하는 프로토콜이라고 언급했습니다. 이번글에서는 웹소켓이 무엇인지 그리고 이를 직접 구현해보도록 하곘습니다. 웹소켓이 HTTP위에서 동작한다는 점은 TCP 위에서 동작한다는 것과 같은 말입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ff5a4367-bd30-49b8-9ba5-8a2e4c1943c0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-24950e59-92af-4b12-b53d-ef55ff1e1216&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히 웹소켓은 로우레벨을 이해하면 좋은점이 있습니다. 만약 거래소 또는 채팅과같이 실시간 데이터를 빠르게 처리해야 한다면 웹소켓을 직접 옵티마이징(최적화) 작업을 해야하거나 직접 구현해야하는 상황이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-96ec51af-1326-4d20-b33b-db77d246ce39&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6c10e5e0-6588-4e9e-ab16-72f2c140687d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;멍선생의 네트워크 강의는 단순히 이론만 설명하지 실제 동작하는 코드를 작성하여 추상적인 개념을 최대한 구체화하는 것을 목표로 하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-957b5998-5609-4799-8c7f-5c0d561377e1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-8ced5c9c-0152-4a20-bfbe-a6ce2c16a42f&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 웹소켓(websocket)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-12136c84-60f0-4757-8067-480dd05e41f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓은 HTTP를 기반으로 양방향 통신을 제공하는 프로토콜입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b48f6099-a718-48df-8d56-f221c6575928&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a18186c7-d814-4819-976f-7b5e783b0bf6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;양방향 통신이라는 것은 클라이언트의 요청없이 서버가 클라이언트에게 메시지를 전달할 수 있다는 것을 의미합니다. 즉, 클라이언트는 최신 데이터를 받기위해 주기적으로 서버에게 요청하는 polling, long polling, stream등을 사용하지 않아도 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dc7b6b63-dd15-4f66-b5d5-6d8cc8913083&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-827b9612-8414-4bc6-bd39-5f48624e8679&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓의 개념은 아주 간단합니다. 앞에서 우리는 TCP로 연결된 두 응용프로그램은 TCP 연결을 끊지 않는다면 즉, socket.end()를 하지 않는다면 서버든 클라이언트든 데이터를 전달하고 전달 받을수 있다는 점을 인지하고 있을것입니다. 여기서 HTTP와 웹소켓의 차이점이 바로 이 부분입니다. 물론 HTTP/1.1은 일정시간 연결을 끊진 않지만 결국 끊기게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-96317968-3640-42c6-b0d5-8d4513e6c842&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b123ed86-1d6c-4f45-90a6-adb756fbe585&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓은 HTTP 요청을 통해 socket.end를 하지 말라고 합니다. 그리고 자체적으로 정의한 데이터프레임 형식에 맞춰 데이터를 주고 받습니다. 이때 socket.end를 하지 말라고 하는 과정을 핸드쉐이크라고 하며 핸드쉐이크 시 HTTP 프로토콜을 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1ca36900-3b6c-4467-92fd-1b11f7880136&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-e84e22fb-b2ac-4807-878a-9cff4f980af2&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 핸드쉐이킹 과정&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0c3067a2-04c9-4f82-8510-b0c40dda8a49&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lT215/btrKMFQCMIx/ywo2QmqTyDqNXoQVKKOxNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lT215/btrKMFQCMIx/ywo2QmqTyDqNXoQVKKOxNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lT215/btrKMFQCMIx/ywo2QmqTyDqNXoQVKKOxNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlT215%2FbtrKMFQCMIx%2Fywo2QmqTyDqNXoQVKKOxNK%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;773&quot; height=&quot;475&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3a74b5da-3483-4e17-857c-5bfec54c63b0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-713b6aa6-69f4-4cfb-ac56-b8c8b646fb1c&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ handshake request&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-106efc59-5ab8-4c97-82e8-844780005c02&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-481929a1-5286-4200-a7e2-67ddffab1ea6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661667065045&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  upgrade: 'websocket',
  connection: 'Upgrade',
  'sec-websocket-version': '13',
  'sec-websocket-key': 'VEX/yDINihxNvSKmffJF+Q==',
  host: 'localhost:5000'
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;SE-c3bcbda3-9dc6-4303-ba07-7c03b827c8b7&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ handshake response&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-23a6e278-fe7a-4634-99d8-ff5660e23679&quot;&gt;
&lt;pre id=&quot;code_1661667078679&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-35c054ed-0e2a-497b-9a72-c3b42d152c1d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8bb3cdc0-8ab1-4238-a981-ec371784ed7d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-f8196d18-da87-499c-b893-71025d62814f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 핸드쉐이크 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-919db17d-ef36-460c-b531-dc219d5f1cb4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓의 핸드쉐이크는 HTTP를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-4d104e13-329a-44aa-a91f-8982bfa44132&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 클라이언트 -&amp;gt; 서버 연결요청&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-b12ede19-d48a-4df0-95c9-5061568b5f81&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓 사용시 클라이언트는 서버에게 다음과 같이 HTTP를 요청합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f9a1fac2-6da4-4f27-a635-50394189b253&quot;&gt;
&lt;pre id=&quot;code_1661667101580&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GET / HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: xJayu5kgUOIvPXQQpegBXQ==
Sec-WebSocket-Version: 13
Host: localhost:5000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-961e6232-b896-46ea-b4ea-890efb455a48&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7bd98335-04bd-43d1-b1df-8786000b8908&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP 헤더의 &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;Connection&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 Upgrade가 되면 HTTP 서버는 해당 요청이 HTTP라고 인식하지 않습니다. 즉, HTTP가 아닌 상위 수준의 프로토콜을 구현할 수 있게 됩니다. &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;upgrade&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: websocket은 업그레이드 할 대상이 websocket이라는 의미입니다. 즉, 해당 요청은 Upgrade이므로 HTTP 프로토콜에서 커네션을 끊거나 유지하거나 관리를 더이상 하지 않습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-80e968f0-9107-4a82-858e-22d5691f8ef3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7689aeec-cc51-4655-a99e-d8f2f12f2339&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;Sec-Websocket-Key&lt;/b&gt;&lt;/span&gt;&lt;span&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;Sec-WebSocket-Version&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 웹소켓 프로토콜에서 사용하는 정보이며 버전은 13이 최신버전 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5bacee4b-8a52-4e4c-b795-063c9c578129&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-58437a30-4e9b-4068-a8e8-d919a2260a25&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nodejs의 HTTP 라이브러리는 connection이 upgrade가 되었을 때 별도로 처리할 수 있도록 핸들링할 수 있도록 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-50e69f36-e17c-4591-b6ea-cc40f0f17b71&quot;&gt;
&lt;pre id=&quot;code_1661667121524&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require(&quot;http&quot;);

const server = http.createServer(function (req, res) {});

server.on(&quot;upgrade&quot;, function (req, socket, head) {
  console.log(req.headers)
  socket.on(&quot;connect&quot;, function () { console.log(&quot;success&quot;); });
  socket.on(&quot;data&quot;, function (data) {
    console.log(data);
    socket.write(data)
  });
});

server.listen(5000, function () {
  console.log(&quot;server is on 5000&quot;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f71fbd05-5583-4282-b740-76688b61d974&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ed588729-c0a7-406f-b26f-ee988ba11510&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 서버를 실행 후 웹 브라우저로 http://localhost:5000을 접속해보세요 on('upgrade')가 반응하지 않습니다. 왜냐하면 브라우저는 HTTP 요청을 하기 때문에 Connection: upgrade가 아닙니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-05d607f2-a95f-49e3-8de3-5983e3e831cf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-621cd562-8dc8-4296-81e0-36eb1153dc14&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661667132060&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;script&amp;gt;
      const ws = new WebSocket('ws://localhost:5000');
    &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-16510fb1-480d-46d9-beb7-6ac12a7d5235&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓 연결을 시도하는 브라우저를 실행해보세요 해당 서버에서 헤더를 출력할겁니다. 그리고 헤더 정보를 보면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-82f7b6f2-e514-4a03-a489-0d9ab1e3c078&quot;&gt;
&lt;pre id=&quot;code_1661667140845&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  upgrade: 'websocket',
  connection: 'Upgrade',
  'sec-websocket-version': '13',
  'sec-websocket-key': 'VEX/yDINihxNvSKmffJF+Q==',
  host: 'localhost:5000'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-29e12c0e-362a-451f-a3dd-cc94690cb23c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IZWfx/btrKGOBLC57/GW5ZI2ktiD0rssUvVCKc6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IZWfx/btrKGOBLC57/GW5ZI2ktiD0rssUvVCKc6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IZWfx/btrKGOBLC57/GW5ZI2ktiD0rssUvVCKc6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIZWfx%2FbtrKGOBLC57%2FGW5ZI2ktiD0rssUvVCKc6k%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;773&quot; height=&quot;413&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c7e2a2b8-d63f-457a-9c75-76c0cc2a64c7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-350e8bfd-b5f9-4e23-8f0a-ded7d9e48eaa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;서버에서 별도의 데이터를 주고있지 않기 때문에 요청 헤더만 존재하고 응답 헤더는 보이지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fa7d9690-a9c3-4181-b8d6-62afe1e870be&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5c9088cf-329d-471c-bebb-afa6dc4c7665&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;websocket 라이브러리를 활용하여 해당 서버에 접속해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9f0ff7f7-c01b-4255-a01a-a211fbba6b04&quot;&gt;
&lt;pre id=&quot;code_1661667150998&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocketClient = require('websocket').client;
const client = new WebSocketClient();

client.connect('ws://localhost:5000/');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-95235c4d-73c2-47ab-b0ae-a71531629807&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c1a0d6d1-cf50-4325-b3e4-0caed8e2ec2d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마찬가지로 서버는 반응합니다. 그렇다면 우리가 직접 net 모듈을 통해 TCP 수준에서 요청을 해본다면?&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-98fb6656-854a-430c-a73f-9963fc69d463&quot;&gt;
&lt;pre id=&quot;code_1661667157557&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// TCP level: 3 way-handshake
const socket = net.connect({ port: 5000 });

socket.on('connect', function () {
  console.log('connected to server!');
  
  const msg = [
    'GET / HTTP/1.1\r\n',
    'Connection: Upgrade\r\n',
    'Upgrade: websocket\r\n',
    'Sec-WebSocket-Version: 13\r\n',
    'Sec-WebSocket-Key: s+92vaV9BEsiNRk0rVmKDA==\r\n',
    'Host: localhost:5000\r\n',
    '\r\n'
  ].join('')

  // HTTP level: 2 way-handshake
  socket.write(msg);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bbea22ea-f196-4dea-8d5c-afb5af2c1f62&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-75fbb2f5-32dc-4c05-93e1-000c12bc22e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 클라이언트 프로그램을 실행하면 서버가 반응합니다. 지금까지 HTTP 프로토콜의 Connection: Upgrade를 알아보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-2fe6c7e4-01c5-494e-b7e1-f0ccd24f6e45&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 서버 -&amp;gt; 클라이언트 연결수락&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-16455e28-b59f-4c60-8f19-a9fae5bb4d38&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;앞에서 Connection: Upgrade, Upgrade: websocket,을 기반으로 Sec-WebSocket-Version과 Sec-WebSocket-Key를 핸드쉐이크를 위해 서버에게 전송했습니다. 서버는 Sec-WebSocket-Key를 이용하여 Sec-WebSocket-Accept를 만듭니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e7730185-13ec-4506-9133-9d5ca7769548&quot;&gt;
&lt;pre id=&quot;code_1661667181353&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6daf6a47-30da-4087-85bd-35589a90b5a7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6a4132a6-a9c9-475a-b19a-4117fdac13cb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Sec-WebsSocket-Accept는 클라이언트가 전달한 Sec-WebSocket-Key와 258EAFA5-E914-47DA-95CA-C5AB0DC85B11를 하나의 문자열로 만듭니다. 그리고 sha1로 해싱한 후 base64로 인코딩한 결과가 Sec-WebSocket-Accept입니다. 그리고 이때 중요한 점은 상태 코드를 101로 해야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-71a2a434-1085-4b4f-be4a-4e82a528f38c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이번의 서버는 http가 아닌 net 모듈을 이용하여 구축을 해보겠습니다. 이왕 로우한 영역으로 내려온거 화끈하게 내려가보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b2675d52-8063-4364-b9ee-1b473f20702f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f26824f-0bc6-4104-be9b-7945d06410fd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661667196078&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');
const crypto = require('crypto');

function handshakeMsg(msg) {
  const websocketKey = msg.split('\n').find(item =&amp;gt; item.includes('Sec-WebSocket-Key'));
  const secWebsocketAccept = websocketKey.split(': ')[1].replace('\n', '').replace('\r', '');
  const salt = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'

  // sha1 해싱된 결과 base64 인코딩
  const sha1 = crypto.createHash('sha1')
  const hashing = sha1.update(secWebsocketAccept + salt).digest('base64');
  
  return 'HTTP/1.1 101 Switching Protocols\r\n' +
         'Upgrade: websocket\r\n' +
         'Connection: Upgrade\r\n' +
         'Sec-WebSocket-Accept: ' + hashing + '\r\n' +
         '\r\n';
}

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    
    console.log('====== handshake start ===== ')
    console.log('request headers')
    console.log(data.toString());

    const msg = handshakeMsg(data.toString());
    console.log('response headers')
    console.log(msg)
    socket.write(msg)
    console.log('====== handshake end ===== ')
  
  });
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-048c4797-44f4-4dc3-af4c-a89db42509d3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;handshakeMsg 함수는 클라이언트가 전달한 Connection: Upgrade, Upgrade: websocket, Sec-WebSocket-Version, Sec-WebSocket-Key 문자열 정보를 파라미터로 넘기면 Sec-WebSocket-Accept를 포함한 결과를 만들어 줍니다. 해당 정보를 클라이언트에게 전달하면 핸드쉐이크가 성공적으로 완료하며 HTTP의 역할은 종료합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-17a88984-8a8a-41e7-bca8-b01d762a4be4&quot;&gt;
&lt;pre id=&quot;code_1661667215823&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocketClient = require('websocket').client;

const client = new WebSocketClient();
client.connect('ws://localhost:5000');

client.on('connect', function(connection) {
    console.log('WebSocket Client Connected');
 });&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b1c36b5b-5256-4879-934a-c3c5fe6e51df&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cdf6defc-5c33-4937-b18d-323d662e388a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;on('connect')는 웹소켓 핸드쉐이크가 성공적으로 완료되었을 때 호출됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0ae3b716-c81f-40cb-bdbb-3e5d94a7543d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-33578c72-b130-49bb-9757-e3be87788405&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #ba0000; font-family: GungSeo, serif;&quot;&gt;&lt;b&gt;※ 주의사항&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-edf97e4c-4195-4f70-8d0d-1ff58e43578d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 한 가지 해깔릴만한 부분을 알려드리겠습니다. 지금 우리는 2개의 라이브러리를 이용하여 클라이언트를 직접 구현해보고 있습니다. 바로 TCP 레이어인 net과 웹소켓 레이어인 websocket입니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-93c83df7-fc81-4e16-9a95-70d610289121&quot;&gt;
&lt;pre id=&quot;code_1661667232922&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
const socket = net.connect({ port: 5000 });

// TCP level: 3 way-handshake 완료시
socket.on('connect', function () {
  console.log('connected to server!');
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c513016c-98fc-4a77-900c-c730290fec48&quot;&gt;
&lt;pre id=&quot;code_1661667239656&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocketClient = require('websocket').client;

const client = new WebSocketClient();
client.connect('ws://localhost:5000');

// HTTP level: 2 way-handshake 완료시
client.on('connect', function(connection) {
    console.log('WebSocket Client Connected');
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3c4fa6f4-6f86-4cad-aeeb-84150e322274&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-db9e7259-5f34-4500-9bef-aad6757d3d1c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;코드의 형태가 유사하죠? 하지만 on('connect')가 호출되는 시점이 다릅니다 각 레이어마다 connect라고 인지하는 시점이 다르기 때문입니다. net에서의 on('connect')는 TCP 수준에서 발생하는 3 way-handshake입니다. 하지만 websocket은 HTTP로 Sec-WebSocket-Key와 Sec-WebSocket-Accept를 성공적으로 주고받았고 클라이언트가 101응답을 받았을 때 on('connect')를 호출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5849ddcf-30e1-4782-be12-7f6bfe5fc5db&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fb0269a2-d4ec-494c-a1c7-e2217ad92e90&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹 브라우저에서도 우리가 만든 웹소켓 서버와 연결을 할 수 있는지 확인해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fee814fa-1bb4-4c97-b224-1159f2ca0d63&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9rlI8/btrKMoBoTpk/DBQyDfOkFpLcphFcDKabKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9rlI8/btrKMoBoTpk/DBQyDfOkFpLcphFcDKabKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9rlI8/btrKMoBoTpk/DBQyDfOkFpLcphFcDKabKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9rlI8%2FbtrKMoBoTpk%2FDBQyDfOkFpLcphFcDKabKK%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;773&quot; height=&quot;436&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;436&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b1dc00d7-0972-4cd1-94f2-9c785c3656f1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6e6723c9-2871-4f88-b2ca-1a88efe3d54b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP 기반으로 핸드쉐이킹을 완료하여 웹소켓 연결이 되었습니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6acbb38e-23cb-47ff-8b10-14a62f7931ac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 연결한 두 프로그램은 웹소켓 데이터프레임을 이용하여 데이터를 주고받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5bdac816-aed7-4227-a622-e0b5f8775236&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 http위에서 구현한다면 다음과 같이 구현할 수 있습니다. 사실상 코드가 거의 유사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d7d87088-9033-46f2-a01f-dfdf4892da59&quot;&gt;
&lt;pre id=&quot;code_1661667253096&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require(&quot;http&quot;);
const crypto = require(&quot;crypto&quot;);

function handshakeMsg(msg) {
  const secWebsocketAccept = msg;
  const salt = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'

  // sha1 해싱된 결과 base64 인코딩
  const sha1 = crypto.createHash('sha1')
  const hashing = sha1.update(secWebsocketAccept + salt).digest('base64');
  
  return 'HTTP/1.1 101 Switching Protocols\r\n' +
         'Upgrade: websocket\r\n' +
         'Connection: Upgrade\r\n' +
         'Sec-WebSocket-Accept: ' + hashing + '\r\n' +
         '\r\n';
}

const server = http.createServer(function (req, res) {});

server.on(&quot;upgrade&quot;, function (req, socket, head) {
  socket.write(headersReturn);
});

server.listen(5000, function () {
  console.log(&quot;server is on 5000&quot;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3db3bc6d-1055-4ec0-8fd7-e09f443605b2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0fbdbf77-c2df-41c0-8f14-44c43d780c50&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-2daad136-f40d-46c3-a401-155997ae6f19&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 데이터프레임&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-6ae280cf-d325-422e-82a8-4fb772a2a699&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓은 다음과 같이 데이터 프레임 포맷을 맞춰야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-777f137c-08b5-4e85-a429-855f6123ba8c&quot;&gt;
&lt;pre id=&quot;code_1661667283233&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; 0               1               2               3
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
 4               5               6               7
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
 8               9               10              11
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
 12              13              14              15
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4a15317a-7cb3-485f-83ce-c367c7561b5a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0a05fa0a-9cb8-4b41-8b3e-a6daba6c14ad&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓의 데이터 프레임은 가변적입니다. 데이터가 가변되는 상황은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-05a2912c-e7d8-4606-ba0e-807f66654497&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 첫 번째 가변상황&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7bbe38fa-5a91-4d07-8c8f-4b1e4f65d683&quot;&gt;
&lt;pre id=&quot;code_1661667298494&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;서버 -&amp;gt; 클라이언트 데이터 전송
클라이언트 -&amp;gt; 서버 데이터 전송&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4c75bc6c-00ba-4ffd-9e01-83a263b07ad6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ce3d0633-10cc-4f0a-bceb-aa53925c69b0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 둘은 동일한 데이터를 전송하더라도 데이터 프레임의 모양이 조금 다릅니다. 클라이언트에서 서버로 데이터를 전송할 땐 마스킹 작업을 합니다. 이를 위해 마스킹 활성비트 1로 활성화하며 마스킹 비트를 포함합니다. 이후 페이로드(실제 데이터)를 마시킹 비트와 XOR 연산 결과를 utf-8 인코딩합니다. 하지만 서버에서 클라이언트로 데이터를 전송할 땐 마스킹 처리를 하지 않습니다. 그렇기 때문에 마스킹 활성 비트는 0으로 설정되며 마스킹 비트는 존재하지 않고 페이로드는 utf-8로만 인코딩처리 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-25715ca1-4440-40eb-9312-c72ec9fb23ba&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 두 번째 가변상황&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-eebc42ad-df76-429d-97fa-6f058103d68e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;데이터 프레임은 페이로드(전달할 데이터)의 길이를 명시합니다. 하지만 데이터 크기에 따라 크기로 사용하는 프레임의 길이가 달라집니다. 기본적으로 페이로드 길이를 표현하기 위해 7비트를 사용하지만 페이로드 길이에 따라 최대 4바이트(32비트)까지 사용합니다. 만약 페이로드의 길이가 7비트보다 작다면 4바이트는 사용하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fe7e0ea3-876c-4ced-b14e-12be75299095&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;데이터 프레임이 가변이 되는 2가지 상황을 알아보았습니다. 이제 데이터 프레임의 각 항목이 의미하는 것이 무엇인지 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f3c8d6e1-b0b9-4950-b694-7a2970990af2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-dcfeddd6-4495-4bd3-a468-903fe2efd4a3&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 데이터 프레임 분석&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-36a2b236-d8b0-49f7-aa81-90c11c0d9872&quot;&gt;
&lt;pre id=&quot;code_1661667327086&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; 0               1               2               3
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-779c4ea5-99e3-4727-b96f-17621de3d9d1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-28f02238-e08b-42a6-8836-322b3e04e264&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 맨 윗줄은 바이트를 의미합니다. 그 디음 0~7은 비트를 의미합니다. 그다음 문자는 패킷의 역할입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-335ced33-f8fd-4b48-8d66-b5ade9e6a29a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;데이터프레임 4바이트는 FIN, RSV1, RSV2, RSV3, opce, MASK, payload len, Extended payload length를 포함합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6055a7c3-0899-40a5-a301-d940f32c195b&quot;&gt;
&lt;pre id=&quot;code_1661667334580&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; 4               5               6               7
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
 8               9               
+ - - - - - - - - - - - - - - - +
|                               |
+-------------------------------+&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5bd34136-98ec-4c86-b829-373d12d4fadb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d57f5967-6929-46be-a6e1-51f689c872d3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Extended payload leng continued는 10번째 바이트인 9라고 적혀있는 부분까지 확장될 수 있습니다. Payload Len은 항상 존재하지만 Extended payload length는 있을수도 없을수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3f09a4bb-b9a0-49fc-93cf-d24489d440b7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bf4a3b9c-0916-416c-b1f2-47e47608280c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;FIN&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 해당 데이터 프레임이 마지막임을 알립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f5413c45-21ef-4f53-83c4-74581875965b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;RSV1, RSV2, RSV3&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 사용되지 않음, 추후 확장될 것을 대비하여 존재&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-645eb781-a334-421b-8b39-d19c09d3f0d3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;opcode&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: opcode에 따라 데이터 형태가 text(0x1 항상 UTF-8입니다)/blob(0x2)인지 구분합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fc8d95d0-e0ca-4a39-81dd-f5f808320f1a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;MASK&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 앞에서 가변 상황 첫번째에서 마스크 활성 비트입니다. 해당 비트가 1일 땐 마스킹 처리가 되어있음을 알립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0ffc835c-d04a-47e9-9d9e-b60b51c80368&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;payload length&lt;/b&gt;&lt;/span&gt;&lt;span&gt;: 페이로드 길이입니다. 해당 값이 126일 땐 2바이트(2~3)를 데이터 길이표현으로 추가적으로 사용하며, 127일 땐 6바이트를 추가적으로 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-99e4cae4-a3ba-4a75-a743-93956d55f679&quot;&gt;
&lt;pre id=&quot;code_1661667342747&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;                                +-------------------------------+
                                 10              11
                                +-------------------------------+
                                |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
 12              13              
+-------------------------------+
| Masking-key (continued)       |   
+--------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-72b5d4ac-89b1-40c2-99f2-793a138ba4a0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b040dc60-542d-4ab2-82e9-ae8b5c0a7381&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;masking-key는 MASK가 1로 활성화되었을 때, 즉 클라이언트가 서버로 데이터 프레임을 전달할 때 Masking-key를 이용하여 페이로드를 마스킹처리 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ac2a1854-13f9-4960-a44b-a078e417f984&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;14(15번째) 바이트 부터 페이로드 입니다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661667353466&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;                                +-------------------------------+
                                 14              15
                                +-------------------------------+
                                |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6bfb8b15-05f1-4611-8ad1-0686e9f028c9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-377ddb11-9850-4d39-b479-26263f6f187e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 중요한 점은 앞에서 payload length가 7비트 고정 8바이트가 가변이기 때문에 Masking-key와 Payload의 위치(offset)는 변할 수 있습니다. 그렇기 때문에 데이터프레임 인코딩/디코딩 시 이 부분을 적절히 신경써줘야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dea65e4c-934c-49c8-8d2e-53cb1a2aba03&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Masking-key와 payload가 다음과 같을때 실제 페이로드는 다음과 같은 연산 작업을 진행하여 만들어 집니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-661bf873-6488-40e2-b13e-001841f01c06&quot;&gt;
&lt;pre id=&quot;code_1661667370123&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Masking-Key: 00000001 00000002 00000003 00000004
payload data: hello world&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ac4eb50e-f23d-413d-b433-4bd2210265e0&quot;&gt;
&lt;pre id=&quot;code_1661667377314&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;h XOR 00000001 연산결과 utf8
e XOR 00000002 연산결과 utf8
l XOR 00000003 연산결과 utf8
l XOR 00000004 연산결과 utf8
o XOR 00000001 연산결과 utf8
띄어쓰기  XOR 00000002 연산결과 utf8
w  XOR 00000003 연산결과 utf8
o  XOR 00000004 연산결과 utf8
r  XOR 00000001 연산결과 utf8
l  XOR 00000002 연산결과 utf8
d  XOR 00000003 연산결과 utf8&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-58a016f5-4c6c-44cb-8b7b-10c163c8137c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-c6db3190-ac13-4cbd-bc61-5947b41da60d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 데이터 프레임 디코딩 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-9dd2de0d-5dcc-455c-a529-731dc895276d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞서서 우리는 데이터 프레임이 가변적인 상황을 알아보았습니다. 여기선 클라이언트가 요청할 땐데이터의 길이가 7비트로 표현할 수 있는 126 이하의 데이터 사이즈만 다룹니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fac50957-1dd2-4b2c-b351-7d329d0e3ebc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 디코딩을 다루는 케이스는 클라이언트가 서버로 데이터를 전달하는 경우입니다. 이때 데이터 프레임은 마스크 활성비트가 1로 활성되었기 때문에 Masking-key로 payload를 xor 연산해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661667396202&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function decode(data) {
  let FIN = data[0] &amp;gt;&amp;gt; 7 == 1;
  let RSV1 = (data[0] &amp;gt;&amp;gt; 6 &amp;amp; 1) == 1;
  let RSV2 = (data[0] &amp;gt;&amp;gt; 5 &amp;amp; 1) == 1;
  let RSV3 = (data[0] &amp;gt;&amp;gt; 4 &amp;amp; 1) == 1;
  let OPCODE = data[0] &amp;amp; 0xf;

  console.log('FIN, RSV1, RSV2, RSV3, OPCODE', convertToBinary1(data[0]))
  console.log(FIN, RSV1, RSV2, RSV3, OPCODE)
  console.log()
  
  const IS_MASK = data[1] &amp;gt;&amp;gt; 7 == 1;
  const PAYLOAD_LENGTH = data[1] &amp;amp; 0x7f;

  console.log(`IS_MASK: ${IS_MASK}, PAYLOAD_LENGTH: ${PAYLOAD_LENGTH}`)

  const MASK = data.slice(2, 6);
  const payload = data.slice(8);
  console.log('mask', MASK)
  console.log('payload', payload)
   
  const buffer = Buffer.alloc(PAYLOAD_LENGTH); //  payload 저장용 버퍼생성

  for (let i = 0 ; i &amp;lt; PAYLOAD_LENGTH ; i++) {
    buffer[i] = data[6 + i] ^ MASK[i % 4]
  }

  return buffer.toString('utf-8')
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-88ea2458-c25a-4ea7-a7fa-8174c2c23ec7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-820a7e9e-21f8-490c-b415-80fb687c992b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-25a785e3-ec31-41ee-bb2e-fbf1fa451b49&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트와 서버는 데이터 프레임을 바이너리를 처리하기 위해 버퍼로 관리합니다. 이 부분은 사용하는 언어 및 라이브러리에 따라 달라질겁니다. 여기서 프레임의 값을 좀 더 편하게 보기위해 2진형태로 변환하는 함수가 convertToBinary1입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4aeb7914-d639-47c3-9672-cc19457e9d3f&quot;&gt;
&lt;pre id=&quot;code_1661667408875&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function convertToBinary1 (number) {
  let num = number;
  let binary = (num % 2).toString();
  for (; num &amp;gt; 1; ) {
      num = parseInt(num / 2);
      binary =  (num % 2) + (binary);
  }
  return binary;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-01b84d51-0eef-43ae-b2d6-e7e74d6c057a&quot;&gt;
&lt;pre id=&quot;code_1661667415342&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const IS_MASK = data[1] &amp;gt;&amp;gt; 7 == 1;
  const PAYLOAD_LENGTH = data[1] &amp;amp; 0x7f;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2ea35fc7-f175-4c46-a9b4-a0f003ed7e3e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-58d73c9a-2c1f-43e9-927f-8c12283832ca&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;IS_MASK에 따라 xor 연산을 할지 말지 판단하며, PAYLOAD_LENGTH에 따라 추가적인 데이터 길이를 위해 필요한 부분이 있는지 달라집니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7df082fe-81d5-4063-90f8-74149ffdf59b&quot;&gt;
&lt;pre id=&quot;code_1661667421203&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const MASK = data.slice(2, 6);
  const payload = data.slice(8);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-35e11d23-f9c7-4f69-a55c-ce3bf0f7c305&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-96bf69ed-e040-4352-885e-1c8f178d7330&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;PAYLOAD_LENGTH에 따라 masking-key를 가져오는 부분과 payload를 가져오는 기준점이 달라집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-883c4629-6e76-4dd4-ac53-c46a03bda447&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MASK가 활성되었기 때문에 xor 연산을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-89ef5b21-4bd8-4765-9c2e-2bbe7be2e98c&quot;&gt;
&lt;pre id=&quot;code_1661667430243&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const buffer = Buffer.alloc(PAYLOAD_LENGTH); //  payload 저장용 버퍼생성
  for (let i = 0 ; i &amp;lt; PAYLOAD_LENGTH ; i++) {
    buffer[i] = data[6 + i] ^ MASK[i % 4]
  }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a59360c2-c8ae-4c6b-a591-a4688ebe9a06&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b9c6184e-91f1-43ef-bc86-2971287fcc75&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 말이죠 물론 xor 연산 결과를 buffer에 넣어줍니다. 버퍼의 사이즈는 미리 정해야 하기 때문에 페이로드 사이즈는 중요합니다. 물론 이를 별도의 버퍼공간을 만들어서 concat하는 방법도 있지만 이럴경우 성능이 떨어집니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b672b335-9530-4378-a829-5a4d376b449a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아마 코드를 보면서 &amp;gt;&amp;gt;, &amp;amp;의 연산자가 많이 나오는것을 보실텐데... 이게 최적화를 위해 비트연산자를 활용한 사례입니다.... 이 부분은 최적화가 정말 중요한 문제라 최대한 비트연산자를 많이 사용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-64efdcc9-a080-4689-b05e-9c6c934f6c03&quot;&gt;
&lt;pre id=&quot;code_1661667444788&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');
const crypto = require('crypto');

function handshakeMsg(msg) {
  const websocketKey = msg.split('\n').find(item =&amp;gt; item.includes('Sec-WebSocket-Key'));
  const secWebsocketAccept = websocketKey.split(': ')[1].replace('\n', '').replace('\r', '');
  const salt = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'

  // sha1 해싱된 결과 base64 인코딩
  const sha1 = crypto.createHash('sha1')
  const hashing = sha1.update(secWebsocketAccept + salt).digest('base64');
  
  return 'HTTP/1.1 101 Switching Protocols\r\n' +
         'Upgrade: websocket\r\n' +
         'Connection: Upgrade\r\n' +
         'Sec-WebSocket-Accept: ' + hashing + '\r\n' +
         '\r\n';
}

function isHandshake(data) {
  return data.split('\n').length &amp;gt; 2;
}

function convertToBinary1 (number) {
  let num = number;
  let binary = (num % 2).toString();
  for (; num &amp;gt; 1; ) {
      num = parseInt(num / 2);
      binary =  (num % 2) + (binary);
  }
  return binary;
}

function decode(data) {
  let FIN = data[0] &amp;gt;&amp;gt; 7 == 1;
  let RSV1 = (data[0] &amp;gt;&amp;gt; 6 &amp;amp; 1) == 1;
  let RSV2 = (data[0] &amp;gt;&amp;gt; 5 &amp;amp; 1) == 1;
  let RSV3 = (data[0] &amp;gt;&amp;gt; 4 &amp;amp; 1) == 1;
  let OPCODE = data[0] &amp;amp; 0xf;

  console.log('FIN, RSV1, RSV2, RSV3, OPCODE', convertToBinary1(data[0]))
  console.log(FIN, RSV1, RSV2, RSV3, OPCODE)
  console.log()
  
  const IS_MASK = data[1] &amp;gt;&amp;gt; 7 == 1;
  const PAYLOAD_LENGTH = data[1] &amp;amp; 0x7f;

  console.log(`IS_MASK: ${IS_MASK}, PAYLOAD_LENGTH: ${PAYLOAD_LENGTH}`)

  const MASK = data.slice(2, 6);
  const payload = data.slice(8);
  console.log('mask', MASK)
  console.log('payload', payload)
   
  const buffer = Buffer.alloc(PAYLOAD_LENGTH); //  payload 저장용 버퍼생성

  for (let i = 0 ; i &amp;lt; PAYLOAD_LENGTH ; i++) {
    buffer[i] = data[6 + i] ^ MASK[i % 4]
  }

  return buffer.toString('utf-8')
}

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    
    if(isHandshake(data.toString())) {
      console.log('====== handshake start ===== ')
      console.log('request headers')
      console.log(data.toString());
  
      const msg = handshakeMsg(data.toString());
      console.log('response headers')
      console.log(msg)
      socket.write(msg)
      console.log('====== handshake end ===== ')
    } else {
      console.log('========= dataframe parse start =========')
      console.log(data)
      console.log('decode: ', decode(data));
      console.log('========= dataframe parse end =========')
    }
  });
})

// 클라이언트 -&amp;gt; 서버 마스킹 해야 함
// 서버 -&amp;gt; 클라이언트 마스킹 안해야 함
server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f0b520ce-5c79-4898-8d0e-5750b70a63d5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-72d0d426-a512-4d78-9914-7403555d07e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버는 연결을 목적으로 하는 핸드쉐이크와 데이터 전달을 목적으로 하는 데이터 프레임의 목적을 구분하기 위해 isHandshake 함수를 이용하여 구분합니다. 연결목적인 경우 HTTP 헤더라 엔터가 존재하므로 엔터존재 유무로 구분하고 있습니다. 실제로는 이렇게 안합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-692edd4f-bd97-4b4a-8349-b9e575c2c3ed&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버를 구동 후 간략하게 클라이언트를 실행하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8892b6b1-d914-41ed-ab91-d7e30324799b&quot;&gt;
&lt;pre id=&quot;code_1661667458436&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocketClient = require('websocket').client;

const client = new WebSocketClient();
client.connect('ws://localhost:5000');

client.on('connect', function(connection) {
    console.log('WebSocket Client Connected');
    
    function sendNumber() {
        if (connection.connected) {
            const data0 = {a: 10};
            console.log('send data', data0)
            connection.send(JSON.stringify(data0))
            setTimeout(sendNumber, 3000);
        }
    }
    sendNumber();
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8b3c6f7d-6570-447a-af37-26e792c14252&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-bafe87f0-63e8-4c2a-b25f-e379e787e79b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;연결이 성공적으로 되었으면 json 형태의 데이터를 문자열로 변환하여 3000ms마다 서버로 전송합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d54a5a9f-d6a5-437b-90b5-af523db1d93a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpemYB/btrKJ5CjZr1/ekv3fcwfaxK3euktie1QsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpemYB/btrKJ5CjZr1/ekv3fcwfaxK3euktie1QsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpemYB/btrKJ5CjZr1/ekv3fcwfaxK3euktie1QsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpemYB%2FbtrKJ5CjZr1%2Fekv3fcwfaxK3euktie1QsK%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;773&quot; height=&quot;435&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4df2bcf3-78ab-405f-a4ce-1a62b1f28db0&quot;&gt;
&lt;pre id=&quot;code_1661667473221&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;script&amp;gt;
      const ws = new WebSocket('ws://localhost:5000');
      setInterval(() =&amp;gt; {
        ws.send('hello world');
      }, 3000)
    &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f76c6168-4397-4ccd-990f-9cdb1425fb52&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b7bbae3f-4d70-4c86-86a9-7fd255a73410&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 브라우저를 실행하면 브라우저에서 우리가 구현한 서버로 인코딩 된 hello world를 전송합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6e5ba797-9521-4fbd-97f7-9afcdeee662e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UOk98/btrKJ5oNqY5/nPOSDQ5xyR1J6YmP10sSn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UOk98/btrKJ5oNqY5/nPOSDQ5xyR1J6YmP10sSn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UOk98/btrKJ5oNqY5/nPOSDQ5xyR1J6YmP10sSn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUOk98%2FbtrKJ5oNqY5%2FnPOSDQ5xyR1J6YmP10sSn1%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;529&quot; height=&quot;510&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;510&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a8212152-6eab-4bf4-9ebc-66288f130a81&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-b6912361-67a3-4c64-8b4b-551d8cc4296c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 데이터 프레임 인코딩 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-099045b9-c322-479b-a5f4-56c20ede2106&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;드디어 이번 여정의 마지막입니다. 우선 중요한 점! 서버에서 클라이언트로 요청할 땐 MASK 처리하지 않습니다. 그러므로 MASK 비트는 0이 됩니다. 그렇다면 Masking-Key는 존재하지 않습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-71bd0231-3da5-4ca6-a165-7ceb8b6f761d&quot;&gt;
&lt;pre id=&quot;code_1661667489313&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function encode(msg) {
  const RES_PAYLOAD_LENGTH = msg.length.toString(2).padStart(8, 0); // 2진수 변환

  const responseBuffer =  Buffer.concat([
    // FIN(1), RSV1(0), RSV2(0), RSV3(0), OPCODE(0001) 
    // 10000001 =&amp;gt; 0x81
    Buffer.from('81'.toString(16), 'hex'),
    // mask + payload_length 서버 -&amp;gt; 클라이언트 시 mask는 0이므로 payload 길이만 가지고 만든다.
    Buffer.from(parseInt(RES_PAYLOAD_LENGTH, 2).toString(16).padStart(2, 0), 'hex'), 
    // 페이로드 메시지 인코딩(UTF-8)
    Buffer.from(msg)
  ])

  return responseBuffer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-641ca396-5ceb-4385-b7ea-76706a7446c6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-16a3dae3-8fe4-4873-b55f-265c437d9342&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 원하는 패킷 모양을 만들어 줍니다. MASK는 이며, 해당 형태는 데이터의 길이가 126이하여야만 합니다. 이 이상이면 데이터 길이를 포함해야 하는 패킷을 더 추가해야하기 때문입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c82f77d3-bde0-476e-9204-09f32f6333af&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 서버 기존에 클라이언트가 데이터를 보내면 서버는 '멍개는 잘 생겼다!!'라는 문구를 해당 클라이언트에게 2번 전송합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-38140ef8-af48-4803-9f10-7d7fc747a584&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 클라이언트가 서버로 보내는 데이터 프레임이라면 MASK는 1이여야 하며 Masking-Key가 추가되고 페이로드와 XOR 연산 후 UTF-8로 인코딩 되어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-24d8b876-1dd9-4508-85dc-36629261af23&quot;&gt;
&lt;pre id=&quot;code_1661667503854&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');
const crypto = require('crypto');

function handshakeMsg(msg) {
  const websocketKey = msg.split('\n').find(item =&amp;gt; item.includes('Sec-WebSocket-Key'));
  const secWebsocketAccept = websocketKey.split(': ')[1].replace('\n', '').replace('\r', '');
  const salt = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'

  // sha1 해싱된 결과 base64 인코딩
  const sha1 = crypto.createHash('sha1')
  const hashing = sha1.update(secWebsocketAccept + salt).digest('base64');
  
  return 'HTTP/1.1 101 Switching Protocols\r\n' +
         'Upgrade: websocket\r\n' +
         'Connection: Upgrade\r\n' +
         'Sec-WebSocket-Accept: ' + hashing + '\r\n' +
         '\r\n';
}

function isHandshake(data) {
  return data.split('\n').length &amp;gt; 2;
}

function convertToBinary1 (number) {
  let num = number;
  let binary = (num % 2).toString();
  for (; num &amp;gt; 1; ) {
      num = parseInt(num / 2);
      binary =  (num % 2) + (binary);
  }
  return binary;
}

function decode(data) {
  let FIN = data[0] &amp;gt;&amp;gt; 7 == 1;
  let RSV1 = (data[0] &amp;gt;&amp;gt; 6 &amp;amp; 1) == 1;
  let RSV2 = (data[0] &amp;gt;&amp;gt; 5 &amp;amp; 1) == 1;
  let RSV3 = (data[0] &amp;gt;&amp;gt; 4 &amp;amp; 1) == 1;
  let OPCODE = data[0] &amp;amp; 0xf;

  console.log('FIN, RSV1, RSV2, RSV3, OPCODE', convertToBinary1(data[0]))
  console.log(FIN, RSV1, RSV2, RSV3, OPCODE)
  console.log()
  
  const IS_MASK = data[1] &amp;gt;&amp;gt; 7 == 1;
  const PAYLOAD_LENGTH = data[1] &amp;amp; 0x7f;

  console.log(`IS_MASK: ${IS_MASK}, PAYLOAD_LENGTH: ${PAYLOAD_LENGTH}`)

  const MASK = data.slice(2, 6);
  const payload = data.slice(8);
  console.log('mask', MASK)
  console.log('payload', payload)
   
  const buffer = Buffer.alloc(PAYLOAD_LENGTH); //  payload 저장용 버퍼생성

  for (let i = 0 ; i &amp;lt; PAYLOAD_LENGTH ; i++) {
    buffer[i] = data[6 + i] ^ MASK[i % 4]
  }

  return buffer.toString('utf-8')
}

function encode(msg) {
  const RES_PAYLOAD_LENGTH = msg.length.toString(2).padStart(8, 0); // 2진수 변환

  const responseBuffer =  Buffer.concat([
    // FIN(1), RSV1(0), RSV2(0), RSV3(0), OPCODE(0001) 
    // 10000001 =&amp;gt; 0x81
    Buffer.from('81'.toString(16), 'hex'),
    // mask + payload_length 서버 -&amp;gt; 클라이언트 시 mask는 0이므로 payload 길이만 가지고 만든다.
    Buffer.from(parseInt(RES_PAYLOAD_LENGTH, 2).toString(16).padStart(2, 0), 'hex'), 
    // 페이로드 메시지 인코딩(UTF-8)
    Buffer.from(msg)
  ])

  return responseBuffer;
}

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    
    if(isHandshake(data.toString())) {
      console.log('====== handshake start ===== ')
      console.log('request headers')
      console.log(data.toString());
  
      const msg = handshakeMsg(data.toString());
      console.log('response headers')
      console.log(msg)
      socket.write(msg)
      console.log('====== handshake end ===== ')
    } else {
      console.log('========= dataframe parse start =========')
      console.log(data)
      console.log('decode: ', decode(data));
      const msgBuffer = encode('abcdefghijk');

      console.log('encode: ', msgBuffer);
      socket.write(msgBuffer)
      socket.write(msgBuffer)
      console.log('========= dataframe parse end =========')
    }
  });
})

// 클라이언트 -&amp;gt; 서버 마스킹 해야 함
// 서버 -&amp;gt; 클라이언트 마스킹 안해야 함
server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3f3541d2-125e-41c5-b99c-7f16b1375d9f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-bedc09e3-5034-4b41-b6a9-d0f963f61ab3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트가 한 번요청하면 서버는 2개의 데이터를 응답합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8417c6a7-e75b-46d8-bc42-9770d64118ca&quot;&gt;
&lt;pre id=&quot;code_1661667519974&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;script&amp;gt;
      const ws = new WebSocket('ws://localhost:5000');
      setInterval(() =&amp;gt; {
        ws.send('hello world');
      }, 3000)

      ws.on('data', data =&amp;gt; {
        console.log(data);
      })
    &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-58172f04-ef6b-4712-a43e-6a0e805c7f26&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0467ad9a-a4c8-48de-b278-8b5660e5afe6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3000ms마다 한 번씩 서버로 hello world데이터를 전달합니다.ws.on('data')는 서버가 전달한 데이터가 있을 때 콜백을 호출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dfec90d4-f92a-4e37-ba90-e451b704fb67&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;616&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vyn3K/btrKHuW9gd1/rbeJ04c7B92DZDCHrwlvrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vyn3K/btrKHuW9gd1/rbeJ04c7B92DZDCHrwlvrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vyn3K/btrKHuW9gd1/rbeJ04c7B92DZDCHrwlvrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVyn3K%2FbtrKHuW9gd1%2FrbeJ04c7B92DZDCHrwlvrK%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;616&quot; height=&quot;565&quot; data-origin-width=&quot;616&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bd3e2ca3-a3fc-460f-ac97-9651a81fd22a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-127becf4-46ad-48c1-a12b-e1f7e4e8d7a8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;websocket으로 구현한 클라이언트라면 다음과 같이 처리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-42a532f2-a682-4f13-ad4a-20a1a8419a83&quot;&gt;
&lt;pre id=&quot;code_1661667529952&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocketClient = require('websocket').client;

const client = new WebSocketClient();
client.connect('ws://localhost:5000');

client.on('connect', function(connection) {
    console.log('WebSocket Client Connected');

    connection.on('message', function(message) {
        console.log(message)
        if (message.type === 'utf8') {
            console.log(&quot;Received: '&quot; + message.utf8Data + &quot;'&quot;);
        }
    });
    
    function sendNumber() {
        if (connection.connected) {
            const data0 = {a: 10};
            console.log('send data', data0)
            connection.send(JSON.stringify(data0))
            setTimeout(sendNumber, 1000);
        }
    }
    sendNumber();
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9d334d18-1550-4fd8-9591-8ddec17bad69&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8d5c8057-2d72-4e8a-9b80-a106e9a1727e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;on('message')를 이용하여 서버가 전달한 데이터를 받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7db0115c-9735-40e9-927d-0dfafe51e0c5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FNU2g/btrKLfkmhci/343z539pKe5zmgnYu9wgH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FNU2g/btrKLfkmhci/343z539pKe5zmgnYu9wgH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FNU2g/btrKLfkmhci/343z539pKe5zmgnYu9wgH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFNU2g%2FbtrKLfkmhci%2F343z539pKe5zmgnYu9wgH1%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;773&quot; height=&quot;502&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b7ceb524-e7b3-4ac0-a145-5343b19aacde&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-095b3e9d-1579-4c79-9953-517a44790562&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 http에서 웹소켓 서버를 구현했다면 TCP 보다 훨씬 깔끔합니다. TCP 입장에선 HTTP랑 websocket의 핸드쉐이크, 데이터프레임 모두 받기 때문에 이를 구분해야 합니다. 하지만 HTTP 위에선 핸드쉐이크가 끝났다면 HTTP 서버는 더이상 웹소켓 클라이언트의 요청을 직접 받지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c60ceb9e-49c1-43b7-9c76-68391fb2fd86&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dcda4e97-89cb-4c16-a7d3-3f0f8f93888b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661667541751&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require(&quot;http&quot;);
const crypto = require(&quot;crypto&quot;);

function handshakeMsg(msg) {
  const secWebsocketAccept = msg;
  const salt = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'

  // sha1 해싱된 결과 base64 인코딩
  const sha1 = crypto.createHash('sha1')
  const hashing = sha1.update(secWebsocketAccept + salt).digest('base64');
  
  return 'HTTP/1.1 101 Switching Protocols\r\n' +
         'Upgrade: websocket\r\n' +
         'Connection: Upgrade\r\n' +
         'Sec-WebSocket-Accept: ' + hashing + '\r\n' +
         '\r\n';
}

// encode, decode, convertToBinary1 함수는 동일하게 사용가능

const server = http.createServer(function (req, res) {
  console.log('123')
});

server.on(&quot;upgrade&quot;, function (req, socket, head) {
  console.log(req.headers)
  let headersReturn = handshakeMsg(req.headers[&quot;sec-websocket-key&quot;])
  socket.write(headersReturn);

  socket.on('data', (data) =&amp;gt; {
    console.log('========= dataframe parse start =========')
    console.log(data)
    console.log('decode: ', decode(data));
    const msgBuffer = encode('abcdefghijk');

    console.log('encode: ', msgBuffer);
    socket.write(msgBuffer)
    socket.write(msgBuffer)
    console.log('========= dataframe parse end =========')
  })
});

server.listen(5000, function () {
  console.log(&quot;server is on 5000&quot;);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-3f1786f7-282b-45a0-add6-addaef9f6a6d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 핸드쉐이크 시 http 라이브러리는 json으로 파싱된 헤더를 사용할 수 있습니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2da23300-945f-4a76-9442-b171006bf069&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP 프로토콜이 아니라 웹소켓 데이터프레임 프로토콜에 맞춰서 통신하기 때문에 http로 동작중인 server.on은 동작하지 않고 socket이 데이터를 수신합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8595ee85-f8e4-420b-8454-c6a4c7686421&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 클라이언트를 TCP로 직접 구현했다면 서버에서 구현했던 데이터프레임 생성을 그대로 가져와야 하지만 가변 데이터 프레임 정책에 따라 인코딩 디코딩을 해야합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e673e487-f804-4e34-9b99-94809c662319&quot;&gt;
&lt;pre id=&quot;code_1661667555784&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// TCP level: 3 way-handshake
const socket = net.connect({ port: 5000 });

let isHandshake = false;

socket.on('connect', function () {
  console.log('connected to server!');
  
  const msg = [
    'GET / HTTP/1.1\r\n',
    'Connection: Upgrade\r\n',
    'Upgrade: websocket\r\n',
    'Sec-WebSocket-Version: 13\r\n',
    'Sec-WebSocket-Key: s+92vaV9BEsiNRk0rVmKDA==\r\n',
    'Host: localhost:5000\r\n',
    '\r\n'
  ].join('')

  // HTTP level: 2 way-handshake
  socket.write(msg);

  setInterval(() =&amp;gt; {
    if (isHandshake) { // handshake 되었을 때만 실행
      socket.write(); // TODO: 인코딩
    }
  }, 1000);
});

// 서버로부터 받은 데이터를 화면에 출력 
socket.on('data', function (data) {
  // TODO: 디코딩 필요
  // 핸드쉐이크 응답과 dataframe을 전달받음

  // 핸드쉐이크 응답을 전달받은 것에 따라 isHandshake를 true로 바꿔준다
  isHandshake = true; 
  console.log(data); 
});

// // 접속이 종료됬을때 메시지 출력 
// // 4 way-handshake
// socket.on('end', function () {
//   console.log('disconnected.');
// });

// // 에러가 발생할때 에러메시지 화면에 출력 
// socket.on('error', function (err) {
//   console.log(err);
// });

// // connection에서 timeout이 발생하면 메시지 출력 
// socket.on('timeout', function () {
//   console.log('connection timeout.');
// });&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e2f40768-9b0a-4db2-876b-bc372f44d621&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1274bb3b-4a4e-4c79-be21-386576c2b652&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;코드의 레이아웃은 대략 이런 모습이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-30e46270-cd26-44bc-b0ec-c9dfbfabb539&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-873d1892-014f-404a-ad05-e10991986a1c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지 TCP와 HTTP 레이어에서 웹소켓을 구현해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b9de564b-d5cd-45f7-9680-efea64890909&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-66171a2e-ea69-4272-af2b-24c96f6db5b1&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● socketio&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-e999ad07-32c1-4060-89f0-be3d1caf0c6c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;socketio는 websocket위에서 동작하는 프로토콜 입니다. 또한 socketio는 커넥션이 끊기면 재연결을 시도하거나 웹소켓을 지원하지 않는 환경에서는 polling과 같은 기술을 사용하여 웹소켓을 대체합니다. transports는 연결을 시도할 프로토콜을 명시합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fe5741de-2229-4308-a0ed-7c9056730428&quot;&gt;
&lt;pre id=&quot;code_1661667570112&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { io } = require(&quot;socket.io-client&quot;);

const socket = io(&quot;ws://localhost:5000&quot;, {
  transports: [&quot;websocket&quot;, &quot;polling&quot;],
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d40f548b-2653-4357-a0aa-4c6d87c9c102&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-66ffea4e-ccff-4f0c-a38d-7a6c16cd69c0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;socket.io-client 또는 socket.io의 CDN을 이용하면 socket.io를 사용할 수 있습니다. socket.io는 transports로 websocket, polling 등을 넣을 수 있습니다. transports에 명시한 순서대로 클라이언트는 연결을 시도합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3734b3ac-d561-4db2-a47d-6fc369b58d22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8c70fc21-3ed9-48d7-943c-26bf5555d28d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;transports는 다음과 같은 종류를 포함할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8ae1f1f6-f1f4-405c-a658-0dd81873e88d&quot;&gt;
&lt;pre id=&quot;code_1661667575236&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;websocket
flashsocket
htmlfile
xhr-polling
jsonp-polling
polling&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-007940ac-1e70-49f3-9a49-ee35b7d1d4dd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ae4ee054-f249-4bc4-85b8-7ab720bce03f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(별의 별 방식이 다 있죠?)&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-343e9c9c-cc74-4f8f-832c-f3b616217c5a&quot;&gt;
&lt;h4 id=&quot;SE-81f53ac4-4dfb-48b6-8a2e-98d9297f3e3a&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ websocket으로 연결 시도시 헤더&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-71e34e51-c021-4501-9aa2-d62ead5eb2ca&quot;&gt;
&lt;pre id=&quot;code_1661667592808&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GET /socket.io/?EIO=4&amp;amp;transport=websocket HTTP/1.1
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: IogOLF9O3PcDxEVa1yCW7A==
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Host: localhost:5000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06b045bf-c55e-4fbb-a70b-c3bf2e031cba&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6e5d7c45-96f6-4409-ac46-647a40780fd9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;socket.io는 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;sec-websocket-extensions&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 포함합니다. &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;sec-websocket-extensions&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 클라이언트가 제공하는 확장 기능을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4beb5b0e-725b-4c06-92fb-3906e254c520&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ polling으로 연결 시도시 헤더&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-17757bde-679a-464d-8b4c-cce66402e46b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-56415a9b-3863-4782-bdac-642da03a6d05&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661667605442&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GET /socket.io/?EIO=4&amp;amp;transport=polling&amp;amp;t=NwOl9RS&amp;amp;b64=1 HTTP/1.1
User-Agent: node-XMLHttpRequest
Accept: */*
Host: localhost:5000
Connection: close&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-f6d97b26-c027-460d-b805-5aaa4d23e546&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 socket.io는 웹소켓의 단점 중 하나인 서버와 클라이언트간 주고받는 메시지를 on('message') 하나의 이벤트로만 처리를 해야합니다. 하지만 서버와 클라이언트는 다양한 형태의 이벤트(즉 엔드포인트)를 구분하는데 이를 편하게 할 수 있도록 개선한 프로토콜이 socket.io입니다. 데이터를 보낼 때 emit('이벤트 명', 전달 할 데이터)를 호출하면 수신자 측에선 on('이벤트 명', 전달받은 데이터)로 데이터를 받을 수 있습니다. emit과 on은 서버와 클라이언트 구분없이 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c6291029-e397-439d-b089-41a1d24e77fe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bd4c2761-996b-42c6-999a-9951c298dbdb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;socket.io의 프로토콜은 다음과 같습니다. 해당 프로토콜은 Namespace(nsp), type, data, id가 포함된 json 구조의 포맷으로 만들어집니다. 확실히 점점 프로토콜의 모습도 발전하고 있는 모습이 보입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9a549570-8d6e-4bd0-b110-abe1ac1d2754&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a545ed47-0b7d-44e6-92d4-53e85f7075d2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/socketio/socket.io-protocol&quot;&gt;https://github.com/socketio/socket.io-protocol&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661667612843&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - socketio/socket.io-protocol: Socket.IO Protocol specification&quot; data-og-description=&quot;Socket.IO Protocol specification. Contribute to socketio/socket.io-protocol development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/socketio/socket.io-protocol&quot; data-og-url=&quot;https://github.com/socketio/socket.io-protocol&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DOaaV/hyPAtk4PtI/pOz3ch6ylqNKsZSwmHlLb0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/socketio/socket.io-protocol&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/socketio/socket.io-protocol&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DOaaV/hyPAtk4PtI/pOz3ch6ylqNKsZSwmHlLb0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - socketio/socket.io-protocol: Socket.IO Protocol specification&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Socket.IO Protocol specification. Contribute to socketio/socket.io-protocol development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>컴퓨터 공학(Computer Science &amp;amp; Engineering))/네트워크</category>
      <category>Handshake</category>
      <category>http</category>
      <category>Protocol</category>
      <category>socketio</category>
      <category>tcp</category>
      <category>websocket</category>
      <category>네트워크</category>
      <category>웹소켓</category>
      <category>핸드쉐이크</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/93</guid>
      <comments>https://meongae.tistory.com/93#entry93comment</comments>
      <pubDate>Sun, 28 Aug 2022 15:20:28 +0900</pubDate>
    </item>
    <item>
      <title>[네트워크] TCP? HTTP? 그것이 알고싶다</title>
      <link>https://meongae.tistory.com/92</link>
      <description>&lt;div id=&quot;SE-9f489071-916f-4c02-a3ca-a60a76c78ddc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-B3CD577F-B8AC-423F-8141-A568C65DD0A1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; TCP와 HTTP를 다뤄보도록 하겠습니다. 근데 사실 어렵지 않아요!!!! 이걸 어렵게 설명하니깐 어려운거지..... 어렵지 않은 이유를 알려드릴게요&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E08D4BA1-2D97-45D8-8245-C0FA5CD08380&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-055006CC-AD11-4C14-9B9C-B4B40F6FD08C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사실 어려운 개념은 맞습니다. 왜냐고요? 우리 눈에 보이지 않으니깐요? &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-57D33204-DDA0-455A-AC37-81B9210624AA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 TCP 레이어 위에서 HTTP를 직접 구현하여 브라우저를 통해 구현한 HTTP를 사용하는 과정을 통해 진입장벽을 낮췄습니다?&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-596D6980-7297-4A59-A6C8-60E7C43C770D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-C7EBB4AF-A345-4E20-9773-2A1E66B32242&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TCP라고 하면 흔히 소켓 프로그래밍, TCP/IP, UDP를 많이 떠올릴것입니다. 전공자가 아니신가요? 모르셔도 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-DD504BDA-56C7-4E8A-90E0-7ECE9A236CAC&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-F6CAF813-992F-474A-A9C1-6936D63A9C05&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 배경지식&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-917A9B7D-6764-4BB0-848C-FA3B89EB7504&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;21세기의 우리는 다양한 프로토콜 기반으로 네트워크를 이용하여 데이터를 주고받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E174E92C-D20E-46A5-93B9-12EA5355491F&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;http, websocket, webrtc 등 이를 제대로 이해하기 위해 이들이 어떻게 구현되는지 알아볼건데 필요한 배경지식을 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4D26FCC7-3253-4669-A789-4DF61307C0EC&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-6234721C-5CA3-4BA4-A93D-E10DEED4A198&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; OSI 7계층&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-F259D5DC-C401-405B-9C7A-7D47CA796D28&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번재로 OSI 7계층입니다. 우리가 네트워크를 공부하면 첫 번째 포기하는 지점입니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9dbbdd50-f984-4f46-af36-94d4fd339781&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kMqi7/btrKHb4yLJs/9k110dD13F42GheB2d57hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kMqi7/btrKHb4yLJs/9k110dD13F42GheB2d57hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kMqi7/btrKHb4yLJs/9k110dD13F42GheB2d57hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkMqi7%2FbtrKHb4yLJs%2F9k110dD13F42GheB2d57hk%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;296&quot; height=&quot;472&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2298f8d9-eec3-4b46-9e69-6f99dce59ed1&quot;&gt;
&lt;p id=&quot;SE-E7387A71-18E7-4FDC-80F2-37C559BC7E80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아래 내용 안외워도 됩니다. 아 이렇구나 하고 그냥 빠르게 넘어가세요 왜냐하면 이를 좀 더 함축적으로 4계층으로 표현하기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-550EA6A8-EAEC-40FA-B633-40949BC05336&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;SE-BB4BD13B-2C11-41AB-ACAE-83228FE5D83E&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 1층 - 물리계층&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-5EE51EF5-67CD-415B-9DD1-3718C775C8FC&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 계층은 통신 케이블을 통해 전달되는 계층입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-F967531D-2A3C-47BD-AA4A-6BF725A34CD8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-9B3D9A15-864E-4EA7-9B6B-CD47E7E05AF9&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 2층 - 데이터 링크 계층&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-159303C3-1B87-4B9F-96DD-E17FAFC7ABB1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;mac address(맥 주소)를 이용하여 정보의 전달을 수행하는 계층입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-37CF051E-E443-43F5-BD4B-10A56C849656&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모뎀의 역할이 1, 2층을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4F07A807-8C61-40E1-A1F1-B510C651E875&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-74C2FD7E-CB68-4C9E-A773-D1CE694EB8F2&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 3층 - 네트워크 계층&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-5E9993B1-E8F3-43DF-A354-B55F7FC6DBF4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;IP를 이용하여 데이터를 목적지까지 전달하는 기능을 수행하는 계층입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-FD9CB069-8C2C-4162-99BB-E67453CFB41E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-F4474A1F-7168-41F9-89EB-1F76C6925AAF&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 4층 - 전송계층&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-1FD196DB-BC89-481D-B921-8BE96D2235D9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;PORT를 이용하여 응용프로그램간 통신을 할 수 있도록 수행하는 계층입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ED60855C-507C-4001-8888-CB7DAA201B08&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크 계층은 컴퓨터를 찾는거라면 전송계층은 찾은 컴퓨터에서 동작하는 특정 응용프로그램을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-B0477072-98A7-4612-A4B3-E7DC28F39DEA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-9F375FF8-5127-4349-B646-AAA4773F2F5F&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 5층 - 세션계층&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-18350C4C-F6AF-406D-B6C3-72F7D52FC427&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;데이터가 통신하기 위한 논리적 연결하는 계층입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9AFA1915-C379-4DC0-B3FC-D28B9FE85C24&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-656643D6-0665-4CF1-9DA1-E9989AC003A4&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 6층 - 표현계층&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-8FE1AD23-E06E-4179-955D-CE86E5CEBF89&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대표적인 기능으로 주고 받는 데이터를 암호화 하는 계층입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9236BF30-E054-4AB9-BA80-B68F89A8A7A5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;SSL, TLS등이 여기에 포함됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9FC67C9A-88C7-4D55-BA9F-3B4EACF6CAB8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-50154DF5-94CC-4D3B-97FC-25F7F4DCD055&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 7층 - 응용계층&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-9312F487-3E0B-4118-92D7-26DC510680B2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;응용 서비스를 수행하는 서비스를 제공하는 계층입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D1D762A6-D129-417F-91E9-B3400290E9B3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;근데 7층은 너무 많죠? 이걸 좀 더 추상화 하여 기능적으로 4계층으로 줄여서 표현합니다. 해당 층이 머라고 설명이 되어있는데 이해가 잘 안될겁니다. 지극히 정상입니다. 아마 계층이라는 단어가 가장 어렵게 느껴질것입니다. 이 계층이라는 개념은 뒤에서 자세히 다뤄볼겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-AE035B41-1349-4EBB-8BD0-CD3E1088B523&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-1BF82955-77A9-416D-A8CD-2D381E0556B4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; OSI 4 계층&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-FD34D630-3262-4645-BCCF-2FA1E0A64C63&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;OSI 7계층을 좀 더 개발자 관점에서 묶은 레이어가 OSI 4 계층입니다. 해당 계층을 TCP/IP라고 표현합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-54c8a450-55ef-4334-acc3-adc866987b5b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;507&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LaWh2/btrKGRrO6fP/k8RGu2cNidmvdhH3zWFSW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LaWh2/btrKGRrO6fP/k8RGu2cNidmvdhH3zWFSW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LaWh2/btrKGRrO6fP/k8RGu2cNidmvdhH3zWFSW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLaWh2%2FbtrKGRrO6fP%2Fk8RGu2cNidmvdhH3zWFSW0%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;652&quot; height=&quot;507&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;507&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9c438eaa-17ab-4397-8ab6-0ebf500172c9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1B731A41-B5E5-4E60-B892-BD39F0E3AADA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;7층이 우측처럼 4층의 모양으로 됩니다. 자! 이제 여기서 한 가지 더 나아가 보겠습니다. 우리는 TCP와 HTTP를 알아본다고 했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6539AA6D-CD89-4F0B-A2A9-D2F8F3A2CAFC&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-A88BF9EC-33E8-47CE-9DD8-968E18AE3BE4&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ L1 - 네트워크 액세스(MAC Address)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-0AF959D6-0235-4226-B248-D08E26E0285B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제로 데이터가 전송되는 과정을 담당하는 계층입니다. 모뎀을 통해 외부로 통신되는 그 과정을 관리하는 계층입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-B81CC477-9B3D-4213-99A2-5E2C7F4F187C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-6B1C58FE-DCE4-4465-A255-903DC9323BF2&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ L2 - 인터넷 계층(IP)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-206F2F0E-A2CC-4A82-8E79-2CF7031396F3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;L2는 모뎀 밖으로 떠나간 데이터가 목적지 컴퓨터를 찾아가기 위한 방법을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-490E58A1-4C2A-41AA-8A30-D9D797B6EA7F&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 데이터를 패킷 또는 프레임이라고 표현합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-368B0938-B1BC-4925-AB50-22BFB8198A38&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-0F50D021-9E5B-4AAA-A02E-9B17373984C6&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ L3 - 전송계층(PORT)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-D9246BB4-90E5-45AD-AC29-84F62CFFCB9D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;L3는 모뎀밖으로 떠나간 패킷은 L2에 의해 목적지 컴퓨터에 잘 도착했습니다. 하지만 해당 패킷이 어떤 프로그램으로 가야할 지 결정해야 하는데 L3가 도착한 목적지에서 어떤 프로그램으로 갈지 결정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-CE6D196B-AB18-4904-B416-E23268E05FD0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-576E7C96-AA92-4C27-A24D-8422D2DA7771&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ L4 - 응용계층&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-9875F459-3AE6-42EB-BC87-D1974E2F282E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;L4는 프로그램에 도착한 패킷이 어떻게 처리될지 결정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D39DDFE2-868F-4621-BE76-CAC8F3B54FBC&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-117A983C-31CD-47E3-8C3F-8457FC15D280&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 이미지에서 L1, L2, 이런 녀석을 하나의 마을이라고 생각하겠습니다. 마을이 있으면 누가 있어야죠? 시민이죠 TCP, HTTP가 바로 각 마을에 서식하는 시민입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4E2C42ED-89B0-48EF-8E6A-73F65D0932AE&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-62109548-2ACE-4F75-9453-188E2C59BD9A&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;OSI 4계층을 중심으로 TCP는 L3 마을에 HTTP는 L4 마을에 살고있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8CF0A6B4-B4EE-4E4B-AAB9-8FA467641DCD&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8C36BDF3-6DC2-4C30-818E-97101817D63D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 2가지 관점에서 레이어를 분석할 수 있습니다. 네트워크 엔지니어는 L1, L2 레이어를 관리합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2F657868-7F3E-4798-BCB9-D7897027BFD8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-B2EA2990-346F-4D5D-9FA7-1A20F20C75F6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일반적으로 우리가 서버를 만든다는 것은 사실 L4의 더 상위 레이어를 의미하지만 최적화 작업을 위해 L3, L4까지 다룹니다. 엇 그럼 OSI의 4계층에서 L3, L4는 OSI 7계층에서 L4, L5, L6, L7을 다 알아야 하나요라는 생각이 들 수 있는데 앞에서 기능적으로 7계층을 4계층으로 묶었다고 했기 때문에 개발하는 관점에서 L5, L6, L7이 나뉘진 않습니다. 물론 아주아주아주아주 로우한 영역으로 들어가면 나뉘어 지겠지만..... 이런 경우는 아주아주아주 특수한 케이스이기 때문에 대부분 OSI 7계층의 L5, L6, L7는 OSI 4계층의 L4 하나의 계층처럼 생각해보 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-938D000A-9C5B-4558-8BF4-5C15C4ADE47E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8BB57ED8-8525-4871-BD7C-7CA82EE7FA1C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정리하면 아 그럼 개발하는 관점에서 OSI 4계층의 L3, L4만 공부하면 됩니다. 전체적으로 내용이 줄어들긴 했지만 이 둘의 개념이 아직까지 명확하지 않을겁니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9F5F9FFD-CA80-45C3-8847-1C7567182FEF&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-01E49A2F-0DA6-4412-B8B8-1A54C7830798&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● L3 - 전송계층(OSI 4계층의 3층)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-FCCED93D-C3B1-413F-8801-8BEE51905560&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;L3는 PORT를 사용하여 컴퓨터로 들어온 패킷이 특정 응용프로그램으로 전달되도록 합니다. L3의 핵심은 실행된 응용프로그램을 PORT로 구분한다는 점입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E8BA6B2A-D49F-413F-BD0E-62BBF0451EF4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E11E99D2-E5CC-4F39-B5FE-AB16E97273F6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 계층의 가장 대표적인 프로토콜은 TCP와 UDP입니다. 여기서 우리는 TCP만 다뤄보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8BA37C47-9EF3-41FA-AB57-48D4B5AF5EE3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-EAAB2C83-B5BE-4AAE-9203-90BC416940BA&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP의 기초개념&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-5BB48C3C-B396-4384-B278-2E3DFFBF68EB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 계층에서 TCP를 다룰때 2가지 어려운 개념이 등장합니다 바로 3 way-handshake와 4 way-handshake입니다. 이는 두 응용프로그램이 데이터 전달 전 커넥션하는 과정을 3 way-handshake라고 하며, 데이터 전달 후 커넥션을 끊는 과정을 4 way-handshake라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-90752AB6-0086-4B5E-960C-DDCF1BCC255C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D16BBD7F-B5EE-47D7-9224-24649D0B6797&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 과정 때문에 TCP는 신뢰도 있는 데이터 전송을 보장합니다. 여기서 신뢰란 전송한 데이터가 반드시 목적지에 도착 한다는 것을 의미합니다. UDP는 별도로 다루지 않지만 UDP는 연결 전/후로 커넥션 과정을 거치지 않기 때문에 신뢰도가 적으며 대신 TCP보다 빠르게 데이터 전송을 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8025EE66-F370-4C66-9C4D-4C65A5429F6C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-C490174B-D48F-4F94-BAD8-735F8DD4A0CB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TCP와 UDP를 구현하는 행위를 소켓 프로그래밍이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4262AD55-B52C-49A2-804E-07B75BED40CB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-EB8BF6A0-D85D-45A9-83A7-22C37287FAFE&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP 서버 구현해보기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-520819E0-1A2A-47B3-B934-061C8DD5501F&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nodejs에서 네이티브로 제공하는 net 모듈이 있습니다. net 모듈을 통해 TCP 서버및 클라이언트를 구현할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-58bd45bf-a5cb-438a-9f28-db843e1ce15c&quot;&gt;
&lt;pre id=&quot;code_1661666217817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    console.log(data.toString())
    socket.write('test')
    socket.end();
  });
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d2e7437d-4310-45a4-af2a-d8143537336c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-31F6ABB2-8530-4CA0-915B-010ED43A846D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 코드를 통해 TCP 서버를 실행합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4c5d5958-b95f-429e-9649-2aaec9103b26&quot;&gt;
&lt;pre id=&quot;code_1661666224729&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo lsof -i -P | grep :$PORT | grep node&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5fa0e442-2f66-4512-95ad-2c7c064a4d61&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5C26346B-9FAE-46F3-B369-5BF255E9FB28&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;:$PORT는 응용프로그램이 바인딩한 포트를 입력해줍니다. 여기서는 5000을 입력하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6bccb232-3178-44e8-8c55-66b92dd9b5ae&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;87&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AI5Us/btrKMoajQ0k/drilxOUdshVWndtOIC3jqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AI5Us/btrKMoajQ0k/drilxOUdshVWndtOIC3jqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AI5Us/btrKMoajQ0k/drilxOUdshVWndtOIC3jqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAI5Us%2FbtrKMoajQ0k%2FdrilxOUdshVWndtOIC3jqK%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;773&quot; height=&quot;87&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;87&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06f8cd56-47ed-495e-be65-0752c586f6e2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-20F0A55E-C9FC-47FE-AA4D-11F8438A402B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 ubuntu 기반의 리눅스 환경이라면 netstat를 사용하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-93dc862d-b9d3-4714-a0b5-defe500e1ecb&quot;&gt;
&lt;pre id=&quot;code_1661666232441&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ netstat -a

$ netstat -antp&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e76863e1-ba8c-49b0-902f-33985dccead1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-EEBE51EB-D1A0-4B34-8377-7FE62DD249EA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;네트워크(TCP, UDP&lt;/b&gt;&lt;/span&gt;&lt;span&gt;) 상태를 조회하면 5000번 포트의 프로세스 상태가 listen인 것을 확인할 수 있습니다. ubuntu라면 netstat로 확인 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-A992C038-6CFE-4896-8BA6-5E3B45107D75&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-B0CA482C-38DA-47FF-B961-5D716FD578E7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;server.listen을 통해 5000번 포트로 연결을 수행합니다. 사용자는 IP:PORT를 통해 해당 어플리케이션과 데이터를 주고 받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-06B9CD44-19A8-4BA3-90B6-1ED24253828E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1E66E0C7-B4DA-454C-9465-4F241F782108&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;net.createServer는 다른 응용프로그램이 연결을 요청하면 내부적으로 3 way-handshake 이후 연결된 세션 객체를 콜백으로 전달합니다. 해당 코드에선 세션 객체를 socket으로 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-C2AA81B1-9EB1-4EF2-8AD8-544EEC95E9CD&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-34793F42-545E-4456-B1B0-55E2ED102702&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;socket.on('data')는 클라이언트가 데이터를 전송할 때 발생하는 이벤트입니다. socket.write()는 데이터를 전달합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E726DC02-79D9-42D8-8656-6B5C8BB96E86&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-90D46C7D-B5E0-4957-BE3E-82F814120400&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;socket.end()가 호출되면 4 way-handshake가 발생하고 커넥션이 끊어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-47DF7283-9524-4656-B274-61130CBBD75C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-7543F298-3C24-4E74-A22B-60EFA002135D&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; TCP 클라이언트 구현해보기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-85226145-64e7-477c-987f-1ce53acb68b8&quot;&gt;
&lt;pre id=&quot;code_1661666291483&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// 3 way-handshake
const socket = net.connect({ port: 5000 });&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-819ff16f-e1fa-4fef-8df6-65f24737b3d0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0ED5E9E5-C96E-47DA-AE7F-CF3A8263BE1E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;net.connect를 통해 TCP 커넥션을 생성합니다. 이때 3 way-handshake가 발생하여 커넥션을 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7823A402-4D20-483F-AA2C-47B21BDC3AAB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3B50CC4E-93E0-4D4C-9A9A-66083D784604&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버가 실행된 상태에서 클라이언트 코드를 실행하면 서버에서 콘솔에 클라이언트 주소가 출력되는 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0db75262-f62e-4cff-9d86-5cc62b375a2d&quot;&gt;
&lt;pre id=&quot;code_1661666300309&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// 3 way-handshake
const socket = net.connect({ port: 5000 });

socket.on('connect', function () {
  console.log('connected to server!');
  setInterval(function () {
    socket.write('mung mung~~');
  }, 1000);
});

// 서버로부터 받은 데이터를 화면에 출력 
socket.on('data', function (chunk) {
  console.log('receive: ' + chunk);
});

// 접속이 종료됬을때 메시지 출력 
// 4 way-handshake
socket.on('end', function () {
  console.log('disconnected.');
});

// 에러가 발생할때 에러메시지 화면에 출력 
socket.on('error', function (err) {
  console.log(err);
});

// connection에서 timeout이 발생하면 메시지 출력 
socket.on('timeout', function () {
  console.log('connection timeout.');
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-344462aa-072f-4ec4-b996-8e5c422467ab&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-FC21339C-A4B0-4036-AD8B-8510928D0F61&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 해당 코드를 실행하면 어떻게 될까요?? &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5532DE6B-9D49-4EFB-B997-4CE3A000D419&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. 클라이언트가 서버에게 mung mung~~ 전송 &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-013B66F2-EBD4-471F-B588-25F0841CA419&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. 서버가 클라이언트에게 메시지를 받으면 test를 다시 클라이언트로 전송&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1F94CACE-433F-49A0-8999-B92111BF3F46&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. 서버는 메시지 전송 후 socket.end()로 4 way-handshake가 발생하여 커넥션이 끊김&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2080FCFE-CE47-4BE8-A2FA-C804F12F07BC&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4. 클라리언트는 1초 후 mung mung~을 전송하려고 시도&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3B7F6036-DEDE-4553-AF7C-FE297B945507&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;5. 커넥션이 끊겼기 때문에 에러발생&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f681b243-96c9-44ac-8b9b-5b5fde6d3698&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;284&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p8DFL/btrKOhWiY8Z/cAHGUM0oI2MLYzkSTMppm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p8DFL/btrKOhWiY8Z/cAHGUM0oI2MLYzkSTMppm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p8DFL/btrKOhWiY8Z/cAHGUM0oI2MLYzkSTMppm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp8DFL%2FbtrKOhWiY8Z%2FcAHGUM0oI2MLYzkSTMppm0%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;773&quot; height=&quot;284&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;284&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4d484a9b-45d8-4bf0-8973-f6cb6ef893f0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-A0A66AD5-E56A-41E7-AD73-B427D37386E1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1초마다 끊어진 커넥션을 이용하여 메시지 전송을 계속 시도하기 때문에 에러가 발생합니다. 서버에서 socket.end가 실행되고 커넥션이 끊기면 클라이언트에서 이벤트를 등록한 socket.on('end')가 실행된 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-E1E6C043-E8D0-497C-A333-10EEEA8F532C&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 4 way-handshake 발생하지 않고 데이터 지속적으로 주고받기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-996DA5F8-32F1-4A28-8D01-C7D57A84CB7E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 한 번 만들어진 커넥션을 클라이언트가 1초마다 메시지를 전송하는 것을 에러없이 받고 싶다면 서버에서 커넥션을 종료하는 socket.end()을 없애면 됩니다. socket.end()를 지운 후 서버를 재실행한 후 클라이언트를 실행해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0e57de28-2814-49f2-8e39-3ac1cbdfb1a9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8E7eP/btrKGPm8oFB/gTOI6alM3eh8Z6csz04uCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8E7eP/btrKGPm8oFB/gTOI6alM3eh8Z6csz04uCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8E7eP/btrKGPm8oFB/gTOI6alM3eh8Z6csz04uCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8E7eP%2FbtrKGPm8oFB%2FgTOI6alM3eh8Z6csz04uCk%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;773&quot; height=&quot;377&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a00b49f4-b24b-4a27-9851-0aca3a40325c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-06EC6E67-0D69-493D-B632-D137FDBE3A9A&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;생성된 커넥션을 끊지 않는다면 지속적으로 데이터를 주고받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-CC2C0C8A-C908-4C2D-BBE2-2282F84CCA52&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 네트워크(TCP/UDP) 상태&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-3EAD3774-3DDE-41E6-8CD2-F4FD8416A10D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 응용프로그램이 커넥션이 끊어지지 않고 데이터를 주고받을 때 네트워크(TCP/UDP) 상태조회를 하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ace45874-cd74-46c9-a8de-fc716c046e01&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;72&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DhfyK/btrKHw1K4AY/EVsAzZJa8T5KFokWN54y0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DhfyK/btrKHw1K4AY/EVsAzZJa8T5KFokWN54y0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DhfyK/btrKHw1K4AY/EVsAzZJa8T5KFokWN54y0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDhfyK%2FbtrKHw1K4AY%2FEVsAzZJa8T5KFokWN54y0K%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;773&quot; height=&quot;72&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;72&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aa4e6de0-f65e-40aa-815d-a1e33ebf9b0b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-DD953819-BE36-4208-8747-236F55B3337A&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3 way-handshake는 다음과 같이 패킷을 주고받으며 두 응용 프로그램의 네트워크 상태는 다음과 같이 전이합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c17a75e5-b168-4676-8629-3bc279da16c7&quot;&gt;
&lt;pre id=&quot;code_1661666341822&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      TCP A                                                TCP B
  1.  CLOSED                                               LISTEN
  2.  SYN-SENT    --&amp;gt; &amp;lt;SEQ=100&amp;gt;&amp;lt;CTL=SYN&amp;gt;               --&amp;gt; SYN-RECEIVED
  3.  ESTABLISHED &amp;lt;-- &amp;lt;SEQ=300&amp;gt;&amp;lt;ACK=101&amp;gt;&amp;lt;CTL=SYN,ACK&amp;gt;  &amp;lt;-- SYN-RECEIVED
  4.  ESTABLISHED --&amp;gt; &amp;lt;SEQ=101&amp;gt;&amp;lt;ACK=301&amp;gt;&amp;lt;CTL=ACK&amp;gt;       --&amp;gt; ESTABLISHED
  5.  ESTABLISHED --&amp;gt; &amp;lt;SEQ=101&amp;gt;&amp;lt;ACK=301&amp;gt;&amp;lt;CTL=ACK&amp;gt;&amp;lt;DATA&amp;gt; --&amp;gt; ESTABLISHED&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1c83c80d-a7ab-42ae-9732-3f35dd74f3ef&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-B5E47598-B1D8-4243-9FD2-291922B5B7F2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결과론적으로 established 상태의 두 응용프로그램은 커넥션을 유지하고 있어 데이터를 주고받을 수 있는 상태를 의미합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2619f562-637d-48c0-9831-dcf7d8946e84&quot;&gt;
&lt;pre id=&quot;code_1661666354248&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 서버 
net.createServer(socket =&amp;gt; {})

// 클라이언트
const socket = net.connect({ port: 5000 });&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ada324f6-f497-418d-b8d1-268286b7a3bc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-D69F0533-EB63-433F-8090-DA4EC40CF459&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 작성한 코드에서 서버와 클라이언트 코드가 바로 저 복잡한 과정을 거쳐 established 상태를 가진 커넥션 객체를 만들어 주는 부분입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cf5e2017-9645-40e4-bd0f-abefd762d7d8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQjLsi/btrKIyrfzPt/zzyekcPePQoNfRIzuVjKxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQjLsi/btrKIyrfzPt/zzyekcPePQoNfRIzuVjKxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQjLsi/btrKIyrfzPt/zzyekcPePQoNfRIzuVjKxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQjLsi%2FbtrKIyrfzPt%2FzzyekcPePQoNfRIzuVjKxk%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;773&quot; height=&quot;497&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;497&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1403e491-0d43-44b0-b04e-33124a378528&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8840F8FB-D028-4DA3-A2C7-C98C2AD1E989&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하나의 클라이언트를 더 실행했습니다. 가장 위가 서버이며 그 아래2개는 클라이언트입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-219626d7-8141-49e5-8146-757d8ae3dc96&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;115&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kV2G7/btrKHt4ZeMl/gV42LhtOvlt7WSto0NeOkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kV2G7/btrKHt4ZeMl/gV42LhtOvlt7WSto0NeOkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kV2G7/btrKHt4ZeMl/gV42LhtOvlt7WSto0NeOkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkV2G7%2FbtrKHt4ZeMl%2FgV42LhtOvlt7WSto0NeOkK%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;773&quot; height=&quot;115&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;115&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a544bf68-aabd-4010-a2e0-dd6128759e0a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-B04DFF55-50C4-4064-8ECC-ED8E8C107436&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크(TCP/UDP) 상태를 조회하면 2개의 결과가 추가되었습니다. 여기서 9378은 TCP 서버이며 5000번 포트가 50071, 50073 포트와 연결된 상태를 의미합니다. 11711, 11796은 우리가 추가로 실행한 클라이언트입니다. 커넥션이 생성되면 OS는 해당 커넥션에게 랜덤하게 포트를 부여합니다. 그리고 로컬호스트의 5000 포트와 연결되어 데이터를 주고받을 수 있습니다.(established 상태이기 때문에)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0038806B-D6A8-4659-AA43-B4C9D981F907&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-02B98EAF-4649-4F4D-8E2D-07DAC3AECBA8&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● L4 - 응용 계층&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-7319B6D0-703E-4F2B-944A-D76A6F481C7A&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;응용 계층은 L3 위에서 동작하는 레이어입니다. 여기서 위에서 동작한다는 것은 L4에서 추가된 데이터가 L3를 통해 전송한다는 것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2160814d-91c8-4cd0-b140-64de3ae7b17c&quot;&gt;
&lt;pre id=&quot;code_1661666369397&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.write('test')&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06c9bab4-494d-4d6d-b210-fd3c4ec1d7e1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5B203563-96D5-4FF9-BF67-699E9E38DCF7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;응용 계층은 established한 상태에서 데이터를 주고받을 때 서버와 클라이언트간 합의한 규칙입니다. 앞에서 L4의 대표적인 예로 HTTP가 있다고 했습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-DB19B9D9-3532-4F3E-9C39-72A9EC07B1EC&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-726A65EB-9EA9-487F-A545-685F3CC6849D&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 프로토콜이란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-BDC996AE-D4E9-465F-B2BF-C8621FC796C6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP를 우리는 프로토콜이라고 부릅니다. 한가지 테스트를 해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e54e0d37-b3f8-4825-aa00-dd06bb294282&quot;&gt;
&lt;pre id=&quot;code_1661666384686&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    console.log(data.toString())
    socket.write('test')
    socket.end();
  });
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-855c9f68-1201-4342-a028-79bec072a23b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7D702342-11FA-48AB-8DE5-140AD3BD1106&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트에게 요청을 받으면 클라이언트에게 전달받은 데이터를 출력한 후 test 문자열을 전송 후 4 way-handshake를 발생시켜 커넥션을 끊습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-41CE322A-7732-433F-AFA5-F5BC52CE9DCD&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 서버를 실행한 후 브라우저로 localhost:5000을 접속해보겠습니다. 아마 브라우저는 별다른 페이지를 띄우진 않습니다. 하지만 서버의 로그를 확인하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-27a57a38-4eb8-4ed4-8df9-db011bce2ce8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;742&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kw4wE/btrKGQGrwmS/kZyK6Eh5aKNDMuGZhVPwT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kw4wE/btrKGQGrwmS/kZyK6Eh5aKNDMuGZhVPwT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kw4wE/btrKGQGrwmS/kZyK6Eh5aKNDMuGZhVPwT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkw4wE%2FbtrKGQGrwmS%2FkZyK6Eh5aKNDMuGZhVPwT1%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;773&quot; height=&quot;742&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;742&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-786c4c80-5aab-4a04-9bbd-4ee50d858d84&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-CC899389-AAF8-40C2-93B4-3E2BC4DD64C6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버의 로그를 확인하면 이상한 문자를 출력합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5F11B986-C150-4C08-B0D6-9AE3E97D24CF&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-33C63348-0909-4FD4-A655-F9BC92E0D0E9&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; HTTP 프로토콜 규약에 맞는 서버&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-98BC47BB-1D92-4B64-8262-F138BA633C56&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;바로 이 부분이 우리가 얘기하는 HTTP 입니다. 네 HTTP 라는것은 바로 write()로 전달하는 데이터입니다. HTTP라는 규칙으로 작성된 문자열입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2899F9BA-EC99-4774-98D5-BD9D99CC36DB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4FF2FB4D-65A4-4072-A884-7BCEDB50B81B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 HTTP 규약에 맞춰 write에 작성해주고 서버 재시작 후 브라우저로 접속해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bb3ea119-d082-4b78-9d25-95f0a6e16d3e&quot;&gt;
&lt;pre id=&quot;code_1661666400463&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

const server = net.createServer(socket =&amp;gt; {
  console.log(`cnnected address: ${socket.address().address}`);
  socket.on('data', (data) =&amp;gt; { 
    console.log('====== receive data======='); 
    const httpMsg = `
HTTP/1.1 200 Success
Connection: close
Content-Length: 1573
Content-Type: text/html; charset=UTF-8
Date: Mon, 20 Aug 2018 07:59:05 GMT

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=en&amp;gt;
  &amp;lt;meta charset=utf-8&amp;gt;
  &amp;lt;title&amp;gt;Wow!!!!&amp;lt;/title&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;test&amp;lt;/h1&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
`

    console.log(data.toString());
    socket.write(httpMsg)
    console.log('====== receive data======='); 
    socket.end();
  });
})

server.listen(5000, function() {
  console.log(`listen on port 5000`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f30b941c-dd1f-45d8-9899-6f693f7d1090&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ntmnv/btrKHcJb2Qi/TLatCk34VMYX5OtNEnE3QK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ntmnv/btrKHcJb2Qi/TLatCk34VMYX5OtNEnE3QK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ntmnv/btrKHcJb2Qi/TLatCk34VMYX5OtNEnE3QK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNtmnv%2FbtrKHcJb2Qi%2FTLatCk34VMYX5OtNEnE3QK%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;637&quot; height=&quot;375&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c3eb2b71-0783-470d-b413-6b9f5f5fe7a1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-D9FDCA83-7A50-47CB-8F50-7A1DB2151FCF&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;브라우저에서 서버가 응답한 HTML 코드를 정상적으로 렌더링한 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b256d070-2c97-43c4-a4f1-0418ad8a1a7c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJongp/btrKMFwkey5/O4EWLjY4p745OmcYs7LcG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJongp/btrKMFwkey5/O4EWLjY4p745OmcYs7LcG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJongp/btrKMFwkey5/O4EWLjY4p745OmcYs7LcG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJongp%2FbtrKMFwkey5%2FO4EWLjY4p745OmcYs7LcG0%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;773&quot; height=&quot;573&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8f910924-aa7e-4814-a624-8e97a64b2182&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-395572C0-7838-46E8-A7C8-1EDB68EED0B3&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; json 응답하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4ee3782f-27d0-435f-b4ac-06be9d66d1e6&quot;&gt;
&lt;pre id=&quot;code_1661666418399&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const httpMsg = `HTTP/1.1 200 Success
Connection: close
Content-Length: 1573
Content-Type: application/json; charset=UTF-8
Date: Mon, 20 Aug 2018 07:59:05 GMT

{
  &quot;name&quot;: &quot;mung&quot;,
  &quot;age&quot;: 30
}
`;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6bdef8b3-29b7-448b-a36f-b28c4398f875&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-C9E3C0D3-7CA9-4C99-A2E3-AF0C7708C66B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 socket.write로 전송하는 데이터가 앞의 문자열과 같다면 해당 데이터는 json으로 인식합니다. Content-Type에 따라 브라우저는 해당 데이터를 HTML 또는 json으로 인식할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-57825e8d-5711-47d1-bf94-777e94ba3b0a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAxA91/btrKK9Lgvl9/rxNeKvfHg2TyGgvuuZhbK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAxA91/btrKK9Lgvl9/rxNeKvfHg2TyGgvuuZhbK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAxA91/btrKK9Lgvl9/rxNeKvfHg2TyGgvuuZhbK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAxA91%2FbtrKK9Lgvl9%2FrxNeKvfHg2TyGgvuuZhbK1%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;773&quot; height=&quot;573&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d0876db9-fc22-42ae-b802-6e347f663d9f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-BE2CB296-D7CD-41ED-B991-3356D3798E21&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 그래서 HTTP 프로토콜은 어떻게 생겨먹었는데?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-1BAB80BB-0C57-404B-B883-B3558C981829&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RFC를 통해 표준을 정의합니다. HTTP/1.1은 RFC 2616에 작성되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-20EF5639-9E80-4011-A1C3-B9C2954548D8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-65420401-CDEB-4420-9040-37876524FC17&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP1.1은 다음 링크에서 어떻게 생겼는지 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-17A44165-CD02-47D4-BC04-FC2CEDA256FA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc2616&quot;&gt;https://datatracker.ietf.org/doc/html/rfc2616&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661666438109&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1&quot; data-og-description=&quot;&quot; data-og-host=&quot;datatracker.ietf.org&quot; data-og-source-url=&quot;https://datatracker.ietf.org/doc/html/rfc2616&quot; data-og-url=&quot;https://datatracker.ietf.org/doc/html/rfc2616&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc2616&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://datatracker.ietf.org/doc/html/rfc2616&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;datatracker.ietf.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8f29ab2f-d62c-45be-8aa4-3ff6d60e7e2d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-77984E36-5BF4-4E76-8AB7-1B1FE6E51354&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-322692A0-AE0F-4AF0-A166-D4CA88DBA5A4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RFC를 기반하여 socket.write()으로 데이터를 전달하면 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3C17065C-3B1F-401F-9D8E-796D8CDF500D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4CA67E84-E1F1-452B-92B1-66F944CFB259&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; HTTP 서버, TCP 클라이언트 통신&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-0AF65361-0CA6-4861-945F-FB35E04614DA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 TCP로 서버를 만든 후 HTTP 프로토콜을 응답했을 때 브라우저가 정상적으로 렌더링하고 json을 응답하는 서버를 구현해보았습니다. 이번엔 반대로 http 라이브러리로 만든 HTTP 서버를 net 라이브러리를 이용하여 요청/응답 과정을 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-FAF413B3-C57B-4B9E-8007-F41229C96DCB&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 서버&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-31e8c4bc-a996-4533-8c3b-69879e0f6f54&quot;&gt;
&lt;pre id=&quot;code_1661666459273&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require('http');
const url = require('url');

const server = http.createServer( (req, res) =&amp;gt; {
  console.log(req.method)
  console.log(req.url)
  res.writeHead(200);
  if (req.method === 'GET' &amp;amp;&amp;amp; req.url === '/') {
    return res.end('mung ');
  } else{
    return res.end('mung mung');
  }
});

server.listen(5000)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-556733a0-cceb-4afb-8957-2ee83816ac9a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-AB527945-0835-4E11-BA86-1E55DC3666BE&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 클라이언트&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f378604b-eeee-45f0-bd32-b1daee5b1e46&quot;&gt;
&lt;pre id=&quot;code_1661666470009&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const net = require('net');

// 서버 5000번 포트로 접속 
// 3 way-handshake
const socket = net.connect({ port: 5000 });

socket.on('connect', function () {
  console.log('connected to server!');
  socket.write('mung mung~~');
});

// 서버로부터 받은 데이터를 화면에 출력 
socket.on('data', function (chunk) {
  console.log('receive: ' + chunk);
});

// 접속이 종료됬을때 메시지 출력 
// 4 way-handshake
socket.on('end', function () {
  console.log('disconnected.');
});

// 에러가 발생할때 에러메시지 화면에 출력 
socket.on('error', function (err) {
  console.log(err);
});

// connection에서 timeout이 발생하면 메시지 출력 
socket.on('timeout', function () {
  console.log('connection timeout.');
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e830eeeb-78de-4950-83f3-96ea38edf703&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-E288BC17-51C4-4421-96A6-DC06F9A38C4D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버를 실행 후 클라이언트를 실행하면 클라이언트는 다음과 같은 메시지를 응답받습니다. 400은 올바른 요청을 하지 않았다는 것을 의미합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b370a1c9-3ce0-4e6c-9d02-e31ccea4f380&quot;&gt;
&lt;pre id=&quot;code_1661666479706&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HTTP/1.1 400 Bad Reques&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cf1ce602-26ad-4d12-bd2e-2a9004bb99d6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-CB697A7D-4E45-42F1-85C7-116AF5860746&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;바로 &quot;mung mung~~&quot;는 HTTP 양식에 맞지않기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3223BEA5-83E8-4321-9600-C0ACA3C8AF0D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-02D28DED-C265-4060-83C7-51BE6D2D4885&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트에서 socket.write(mung mung~)을 HTTP 규격에 맞춰서 다음과 같이 전송하면 HTTP 서버는 정상적으로 처리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-78f92342-2d73-4bcb-9b10-30f9c80eaf88&quot;&gt;
&lt;pre id=&quot;code_1661666487746&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.on('connect', function () {
  console.log('connected to server!');
  const msg = [
    'GET / HTTP/1.1',
    'Accept: */*',
    'User-Agent: my-test-agent',
    'Host: localhost:5000',
    '',
    '',
  ].join('\r\n')
  socket.write(msg);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8ffa478c-00fe-4094-a4ab-5b1d00aed257&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xtufu/btrKIy5PDf8/2Z4L4dmPV2VwC3Qy2DZuTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xtufu/btrKIy5PDf8/2Z4L4dmPV2VwC3Qy2DZuTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xtufu/btrKIy5PDf8/2Z4L4dmPV2VwC3Qy2DZuTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxtufu%2FbtrKIy5PDf8%2F2Z4L4dmPV2VwC3Qy2DZuTK%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;773&quot; height=&quot;254&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bfbf8ad2-a24a-46ff-a31f-69cbb3faa8f5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1432AEE3-66A8-461A-BD88-71026332C4A2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;GET 메서드의 /으로 요청한 결과를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-23FA6813-9666-4899-B807-56892A163FA2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;/a로 요청하고 싶다면 다음과 같이 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06b65b5f-9e39-47de-a8ae-75494daf3f24&quot;&gt;
&lt;pre id=&quot;code_1661666495985&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;socket.on('connect', function () {
  console.log('connected to server!');
  const msg = [
    'GET /a HTTP/1.1',
    'Accept: */*',
    'User-Agent: my-test-agent',
    'Host: localhost:5000',
    '',
    '',
  ].join('\r\n')
  socket.write(msg);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-81481a3c-db34-4610-8060-61b34f4713f8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nvqVe/btrKOIffMf2/MYUvxQk5pMefBNvW14mLvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nvqVe/btrKOIffMf2/MYUvxQk5pMefBNvW14mLvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nvqVe/btrKOIffMf2/MYUvxQk5pMefBNvW14mLvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnvqVe%2FbtrKOIffMf2%2FMYUvxQk5pMefBNvW14mLvK%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;773&quot; height=&quot;239&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-12838bc0-d077-4711-bcd2-87814d3bb6e2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-A3F91140-E6C3-4952-B07F-5AC8754E4862&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-6A76BC7D-13F5-4068-AB04-B896756019C6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 그 외의 프로토콜&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-348343C8-27E0-465A-BD03-6D815DA35FB8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 시점에서 HTTP 프로토콜을 제외하고 많이 사용하는 프로토콜은 웹소켓이 있습니다. 일반적으로 웹소켓은 HTTP를 좀 더 개량하여 사용한 방법입니다. 웹소켓도 HTTP와 개념은 동일합니다. HTTP는 한 번 데이터를 주고 받으면 커넥션을 끊지만 웹소켓은 끊지 않습니다. 웹소켓은 HTTP 통신을 한 번 주고받고 웹소켓으로 업그레이드 되는 형태로 프로토콜이 구성되어 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9A4FE1E5-381B-4648-A517-90B92879F8A0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8A2B7450-29AC-4A49-BF7C-49BC07AA8588&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉 정리하면 HTTP나 웹소켓은 두 응용프로그램간 연결된 상태(ESTABLISHED)에서 데이터를 주고 받을 때 HTTP는 한 번의 데이터를 주고 받으면 커넥션을 끊으며, 웹 소켓은 끊지 않는 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8798f1ec-8cf2-4b3f-a5a6-3591905b4d36&quot;&gt;
&lt;pre id=&quot;code_1661666514002&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GET / HTTP/1.1
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: J7dCBYk6vVIqwcI/0+CUWQ==
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Host: 127.0.0.1:5000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3c5591db-4bd4-4121-827f-d1db3f632c7f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0CA215BE-BDC9-482B-9C80-026CDF5EC598&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹소켓의 경우는 커넥션 후 데이터를 전송할 때 Connection은 Upgrade, Upgrade는 websocket으로 설정된다는 특징을 가지고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8BBC42D4-15A4-4096-82DF-54022EBBFCAF&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9DDA517C-1B38-49D3-B60D-9A39EC10DA99&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정리하면 L3는 데이터를 전송하기 위한 커넥션을 만들면 L4에선 정해진 규격을 맞춰 데이터를 주고 받습니다. 여기서 정해진 규격을 프로토콜이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b879d7ed-d1f4-40ac-86e8-32a01a072378&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/POuIW/btrKIryNMUE/D8GcgmLejIRKYCP9yym1r1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/POuIW/btrKIryNMUE/D8GcgmLejIRKYCP9yym1r1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/POuIW/btrKIryNMUE/D8GcgmLejIRKYCP9yym1r1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPOuIW%2FbtrKIryNMUE%2FD8GcgmLejIRKYCP9yym1r1%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;533&quot; height=&quot;370&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-49cae0b9-9d80-492f-a6ca-7d3eb417c5e4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-EA7677F0-B7D6-435F-A722-703BD3002A11&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4471B864-66CE-4E9D-80E4-9EA8E0317B70&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;응용계층을 정리하면 HTTP는 TCP위에서 정의한 데이터를 주고받는 규격입니다. 이때 HTTP를 좀 더 확장한 개념으로 웹소켓을 사용합니다. 웹소켓과 HTTP를 좀 더 유연하게 사용하기 위해 socket.io와 같은 라이브러리가 탄생했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E0A7DC24-DDF3-4F36-9C3F-F9635686D181&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-37DDEF1B-C2A7-400E-80AD-2AA2E8700200&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또 UDP를 이용한 방식으로 요즘 많이 핫해지고 있는 webRTC가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-B08DDF42-410C-4304-9F56-4E2968178928&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-122B0DA8-D6F9-4480-A1A3-47ADAF2548AD&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● L5 - 라이브러리 계층&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-B7B9F211-F711-4284-9216-320092C760E4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자 이제 본격적으로 HTTP 서버를 만든다고 생각해보겠습니다. 그럼 우리는 클라이언트가 전달한 매번 클라이언트한테 요청받은 데이터를 매번 파싱해서 쓰는건 말이 안됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D4AA7D90-C086-437D-87DA-9FD0FC541CD7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-034E5089-AC09-4EB9-965E-38D65784BCCB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 앞에서 클라이언트에게 전달받은 HTTP 본문을 파싱하고 write를 이용하여 응답하는 부분을 좀 더 편리하게 추상화한 라이브러리인 http를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2072f4a5-8f50-4939-a74a-a72c10cfc4cf&quot;&gt;
&lt;pre id=&quot;code_1661666531554&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require('http');
const url = require('url');

const server = http.createServer( (req, res) =&amp;gt; {
  console.log(req.method)
  console.log(req.url)
  res.writeHead(200);
  res.end('mung mung');
});

server.listen(5000)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7a1764b3-1723-43ae-a46c-c99c4cc161bf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1AE2303A-7DD9-4829-A840-169EFE14EADF&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;http 라이브러리는 요청 객체와 응답 객체를 이용하여 클라이언트의 요청 데이터를 확인하고 응답할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b895f29b-7ec4-4ae5-9383-99677644329e&quot;&gt;
&lt;pre id=&quot;code_1661666537875&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(req, res) =&amp;gt; {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-03572664-9921-4e63-8638-33074a505a22&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-FFA4F6E3-4E57-409A-8D00-7A21FABC0145&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;established&lt;/b&gt;가 되어 데이터를 주고받을 수 있는 상태가 되면 클라이언트가 전달한 HTTP 본문을 첫 번째 객체인 요청 객체로 만들어주며 socket.write를 추상화하여 사용할 수 있는 두 번째 인자로 전달한 응답 객체를 전달받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-55deb934-0b16-4a90-a566-16b2f7170450&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfT48f/btrKGopO9CB/qMsowTBN90txshWF8n9RD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfT48f/btrKGopO9CB/qMsowTBN90txshWF8n9RD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfT48f/btrKGopO9CB/qMsowTBN90txshWF8n9RD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfT48f%2FbtrKGopO9CB%2FqMsowTBN90txshWF8n9RD1%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;637&quot; height=&quot;375&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5065e4a1-5665-4808-91e8-cb240e188cdd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1uyHV/btrKME5fAdZ/kBxvg638Ujx1Ekpq0hVqLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1uyHV/btrKME5fAdZ/kBxvg638Ujx1Ekpq0hVqLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1uyHV/btrKME5fAdZ/kBxvg638Ujx1Ekpq0hVqLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1uyHV%2FbtrKME5fAdZ%2FkBxvg638Ujx1Ekpq0hVqLK%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;637&quot; height=&quot;375&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-676bcff5-7d6b-4d54-87ec-6dbc60f56b16&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-CB74A38E-87C1-4B0B-ADB7-C21288560285&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;브라우저 및 HTTP 클라이언트 프로그램으로 localhost:5000, localhost:5000/a로 접속하면 서버는 다음과 같이 로그를 출력합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661666550676&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GET
/a
GET
/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0def7f98-8f75-463a-a2f9-328ae51ac987&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-03E490DA-8522-44EE-9E4C-66217034717A&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP 서버를 만들 땐 method와 url을 이용하여 서로 다른 데이터를 응답하는 형태로 만들게 됩니다. 이를 API라고도 하죠&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D935E631-618F-421A-9347-5D2F711A4A65&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-EBC47453-8BDC-4BE3-A418-6BAEE47FD108&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; method와 url에 따라 다른 데이터 응답하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-384770e5-1436-4c92-9bd1-03144ea819dd&quot;&gt;
&lt;pre id=&quot;code_1661666563339&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require('http');
const url = require('url');

const server = http.createServer( (req, res) =&amp;gt; {
  console.log(req.method)
  console.log(req.url)
  res.writeHead(200);
  if (req.method === 'GET' &amp;amp;&amp;amp; req.url === '/') {
    res.end('mung ');
  } else{
    res.end('mung mung');
  }
});

server.listen(5000)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ef7a87fc-3185-4f6f-aad6-ceb5596dc84f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blpln9/btrKLfYXpUP/pJep4ccCvXZXsawo4aRZvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blpln9/btrKLfYXpUP/pJep4ccCvXZXsawo4aRZvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blpln9/btrKLfYXpUP/pJep4ccCvXZXsawo4aRZvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fblpln9%2FbtrKLfYXpUP%2FpJep4ccCvXZXsawo4aRZvk%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;643&quot; height=&quot;375&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-de7473f0-24ad-40ab-875e-d9e50b622a46&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck08LI/btrKOIM5gei/HYFgzPI2gC7LouivIjx2J1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck08LI/btrKOIM5gei/HYFgzPI2gC7LouivIjx2J1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck08LI/btrKOIM5gei/HYFgzPI2gC7LouivIjx2J1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck08LI%2FbtrKOIM5gei%2FHYFgzPI2gC7LouivIjx2J1%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;643&quot; height=&quot;375&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bf34548a-94f3-47d2-a38f-e544203846e6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4F0F30CF-EF91-4891-B639-80AF2B731F30&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서로 다른데이터를 응답받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-C782B4C7-6F04-48A4-B913-FB1A39AD2DD8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-5EF710D8-2705-4029-BE11-A6BF5F33FB3A&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● L6 - 프레임워크&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-AFAAB5E9-DA41-4371-B684-1ACCCAF51CFB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 이 또한 귀찮습니다. 먼가 코드를 유지보수하기 힘든 부분도 있을것이고 좀더 체계화할 수 있는 여러 프레임워크가 나오고 있습니다. 자바의 스프링, 노드의 express, nest, koa 등, 파이썬의 django, flask, fastapi 등 여러 프레임워크가 쏟아져 나오고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8CE27FF3-D545-4086-A7CC-D9543933A9D9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0670038A-D003-428A-8616-EAB6D6F68404&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를들어 여기서 언급한 프레임워크들은 각 언어에서 제공하는 http를 기반으로 보다 편하게 사용할 수 있도록 기능이 추가된 것들입니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3af80f62-2169-424b-a911-28cf1b602611&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d84cd26e-13b2-4033-9073-c3158bd5da66&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661666575940&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) =&amp;gt; {
  res.send('mung!')
})

app.get('/a', (req, res) =&amp;gt; {
  res.send('mung mung!')
})

app.listen(port, () =&amp;gt; {
  console.log(`Example app listening on port ${port}`)
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-AAE6C25D-9294-45B6-86D8-F7B8E3FA98CF&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 기타&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 id=&quot;SE-3C9FD7EE-27AA-475D-BAA7-A1854E857DCF&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; socket.io&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-07FA0BFB-9B63-4EA5-B20D-CE24FC922218&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;socket.io 라는 라이브러리가 있습니다. socket.io는 HTTP와 WebSocket을 둘 다 지원하는 라이브러리입니다. socket.io는 L3에 비하면 상당히 추상화 된 레이어입니다. socket.io는 L3(전송계층)를 구현하지 않습니다. HTTP와 WebSocket 위의 레이어에서 WebSocket을 지원하지 않는 환경에서 HTTP를 이용하여 주기적으로 요청하는 폴링 기법을 지원합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;SE-D049D25F-5886-4076-A862-174173C92311&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; UDP&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-48F42146-9974-4649-BC3D-3A4762F3602B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;L3의 전송계층에서 TCP를 다뤄봤는데 UDP를 다루지 않으면 UDP가 삐질테니 UDP를 빠르게 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-A5258E20-71EA-4BB6-A617-F52814817CD4&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 서버&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1e23dbac-082d-42b0-8ad4-f3f3be8cd5f5&quot;&gt;
&lt;pre id=&quot;code_1661666618805&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const port = 5000;
 
server.on('message', (message, info) =&amp;gt; {
  console.log(`message: ${message.toString()}`);
  console.log(`from address: ${info.address} port: ${info.port}`);
});
 
server.on('listening', () =&amp;gt; {
  const address = server.address();
  console.log(`listening ${address.address}:${address.port}`);
});
 
server.bind(port);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f9f31f7-6d96-4323-9cc8-8770b03bad9f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-6FC8877E-5129-46DF-BBBF-78AAEB3F939C&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 클라이언트&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4841dc4b-30b3-422b-83a0-889e59d39396&quot;&gt;
&lt;pre id=&quot;code_1661666625157&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const dgram = require('dgram');
const toHost = '0.0.0.0';
const toPort = 5000;
const client = dgram.createSocket('udp4');
 
const data = Buffer.from('mung');
 
client.send(data, toPort, toHost, (err) =&amp;gt; {
  if (err) console.log(err);
  else console.log('ok');
  client.close();
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0760930d-331f-435e-8403-ab7bf499b9a3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3B13B670-388C-456A-B8FF-A621CEBD3CE6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아무생각없이 보면 TCP랑 다를게 없는데? 할 수 있을텐데 잘 보면 클라이언트에서 connect하는 코드가 없습니다. UDP는 커넥션 생성 -&amp;gt; 데이터 전송 -&amp;gt; 커넥션 제거 과정없이 데이터 전송을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-F02C4E89-0484-45F6-AE6F-63FCD70F28ED&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3C6EFFC3-DF1F-4878-9895-7A79B2DE26F3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;엥? 그럼 데이터 전송이 안될 수 있지 않나? &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1BE8B964-FB5F-4D89-BEBE-4551CE067AEB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4BDF7E22-3D2B-4A1C-9217-E9001DB09CC2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네 맞습니다. UDP는 데이터 전송을 보장하지 않습니다. 그렇기 때문에 일반적으로 데이터 전송을 보장해야 하므로 TCP 기반으로 구현된 HTTP, WebSocket 등을 많이 사용합니다. 하지만 요즘 UDP를 활용한 프로토콜이 핫해지고 있습니다. 바로 webRTC 입니다. 머 사실 webRTC는 내부적으로 복잡한 통신을 주고 받는데 모든 통신을 UDP로 구성되어 있진 않습니다. TCP와 UDP를 혼용하여 사용합니다. webRTC의 UDP는 UDP로 구현된 SCTP를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E1959BBD-9603-4027-AAA8-E60AC66CCE4E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-7DF54BAE-0042-427C-B2F5-6AC83639F787&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● HTTP/1.1, HTTP/2.0, HTTP/3.0&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-C82B92B3-7B58-4C8B-8EAA-131D10796D76&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 가장 많이 사용하고 있는 HTTP 버전은 1.1입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0E383A46-1E98-4006-8752-940191AF518C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-421E5461-65B3-49DC-90EF-8C990765E6F4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/1.1도 단점이 많아 이를 개선한 방법이 HTTP/2.0, HTTP/3.0입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-EC2D0F58-241E-4EAF-83F2-282AEB9F8C0F&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-A9762AF7-D2B7-4C4E-93CA-58E993A4991C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/2.0은 SPDY를 기반으로 구현합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-378DF008-510F-446F-A798-18C2DC7BF5CB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/3.0은 QUIC를 기반으로 구현합니다. QUIC는 UDP 기반으로 만들어져있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-90E3B4DB-8B5B-440A-B411-CA5A6AB77EDD&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-1E1B7AF9-1A3C-4F9F-B761-BB533F7FE60E&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; HTTP/1.1&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-E8FF0674-AD1B-426B-904C-F33DE39DC623&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/1.1은 connection: keep-alive를 이용하여 커넥션을 제거하지 않습니다. 앞에서 만든 http 모듈로 구축한 HTTP 서버를 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1841e5fe-f866-492e-8744-75fac1bfaaf8&quot;&gt;
&lt;pre id=&quot;code_1661666646454&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const http = require('http');
const url = require('url');

const server = http.createServer( (req, res) =&amp;gt; {
  console.log(req.method)
  console.log(req.url)
  res.writeHead(200);
  if (req.method === 'GET' &amp;amp;&amp;amp; req.url === '/') {
    return res.end('mung ');
  } else{
    return res.end('mung mung');
  }
});

server.listen(5000)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d389baea-b2b2-4a74-b67c-1fd2686f3a57&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyWuip/btrKHVGVA47/YkKuyLJ5bfxETs7m5QcfZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyWuip/btrKHVGVA47/YkKuyLJ5bfxETs7m5QcfZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyWuip/btrKHVGVA47/YkKuyLJ5bfxETs7m5QcfZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyWuip%2FbtrKHVGVA47%2FYkKuyLJ5bfxETs7m5QcfZK%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;773&quot; height=&quot;313&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;313&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-84e5dd58-fdb6-46b2-984d-1dadb4fea5fe&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFjZnp/btrKME5fAbB/uBb4mLL0hHZA6ZYUEHANDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFjZnp/btrKME5fAbB/uBb4mLL0hHZA6ZYUEHANDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFjZnp/btrKME5fAbB/uBb4mLL0hHZA6ZYUEHANDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFjZnp%2FbtrKME5fAbB%2FuBb4mLL0hHZA6ZYUEHANDk%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;773&quot; height=&quot;117&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-54022bdf-eb53-41e8-bde0-a26742bc2a36&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-F977DC18-64DB-4CEB-B540-2681C63CF2EF&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;응답을 정상적으로 마쳤지만 ESTABLISHED 상태를 유지합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D6CD2BA3-E45F-421A-B901-23A1F4D45769&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-097256CD-CDA6-4333-829F-E4F01A85BF2F&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;동일한 커넥션을 가지고 데이터를 지속적으로 주고 받는지 테스트 하기 위해 요청하는 코드를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7cbbd38d-cf8d-44cd-bb86-3df7b4d32d46&quot;&gt;
&lt;pre id=&quot;code_1661666653358&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setInterval(async () =&amp;gt; {
    await fetch('http://127.0.0.1:5000')
}, 300)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0cc75cde-77dd-4f23-a1c7-ad5e97506916&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4EA3237D-2304-44D2-A304-D52622141152&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 127.0.0.1:5000으로 접속한 페이지에서 개발자 도구를 연 후 해당 스크립트 코드를 실행합니다. 해당 코드는 300ms 마다 127.0.0.1:5000로 요청하는 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1f13db09-bbbf-4dfd-a4cf-1c7dea2ca21b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FKemH/btrKGOogvv9/ycESzP1KkKlxK9ZyJnSNxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FKemH/btrKGOogvv9/ycESzP1KkKlxK9ZyJnSNxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FKemH/btrKGOogvv9/ycESzP1KkKlxK9ZyJnSNxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFKemH%2FbtrKGOogvv9%2FycESzP1KkKlxK9ZyJnSNxK%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;773&quot; height=&quot;206&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-66d87d2b-5788-4990-85ed-41d8c74a4108&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-48296E3D-F6FA-48DE-8FA0-918796B93A83&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주기적으로 네트워크 상태를 살펴보면 동일한 커넥션이 유지되고 있는 모습을 확인할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1565417D-76CD-400D-97C5-67BD7CA8790C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-C5E3CF1C-F3E5-40A8-B85C-1B63CCED037E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;커넥션을 유지하여 데이터를 주고받는 과정을 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;Pipelining&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;span&gt;이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D8D12A18-40E0-4F46-9025-751ED50336E7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-9336016E-8579-4477-9361-CF23558EAFDD&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ CLOSE_WAIT&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c1026055-60b8-445b-92ee-f8ba91ddcaf3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnmlfj/btrKGn5tqOp/qv5ukhJIJ5kRXgqTLmYOg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnmlfj/btrKGn5tqOp/qv5ukhJIJ5kRXgqTLmYOg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnmlfj/btrKGn5tqOp/qv5ukhJIJ5kRXgqTLmYOg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbnmlfj%2FbtrKGn5tqOp%2Fqv5ukhJIJ5kRXgqTLmYOg0%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;773&quot; height=&quot;69&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-42f624a0-a86d-4416-a6e9-8c6da223c2bc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6942F248-6AF6-423D-8109-7D540CB9BB66&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CLOSE_WAIT 상태를 만들고 싶다면 HTTP 서버를 열고 브라우저에서 해당 서버를 접속합니다. 그러면 ESTABLISHED 상태가 되는데 이때 서버를 종료하고 네트워크 상태를 확인하면 앞의 이미지처럼 CLOSE_WAIT 상태로 바뀐 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E809B901-B342-41EF-ADA1-8D24E9ABDD11&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-93D53B15-E6F9-4FDF-A32D-0C4A3BD47EA2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CLOSE_WAIT는 두 응용프로그램에서 한쪽이 커넥션을 끊은 상황을 의미합니다. 행아웃이라고도 합니다. CLOSE_WAIT는 이미 커넥션이 끊겼기 때문에 해당 커넥션을 다시 재사용할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E720747D-ED92-4103-A8A6-5FBED359247C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-B3706DF6-0DFB-4606-B6E0-AEA168274DB3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CLOSE_WAIT말고 TIME_OUT도 있는데 이는 재사용 가능합니다. 네트워크 상태는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b4b63321-6475-4465-978e-c6c9aa7eec45&quot;&gt;
&lt;pre id=&quot;code_1661666668483&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CLOSE	    커넥션 없음
LISTEN	    Passive open, SYN을 기다리는 상태
SYN-SENT	SYN을 보내고 ACK를 기다리는 상태
SYN-RCVD	SYN+ACK을 보내고 ACK를 기다리는 상태

ESTABLISHED	커넥션이 생성된 상태, 데이터를 전송할 수 있다.

FIN-WAIT-1	첫 FIN이 보내진 상태, ACK를 기다리고 있다.
FIN-WAIT-2	첫 FIN에 대한 ACK를 받은 상태, 2번째 FIN을 기다리고 있다.
CLOSE-WAIT	첫 FIN을 받고 ACK를 보낸 상태, 어플리케이션의 종료를 기다리고 있다.
TIME-WAIT	2번째 FIN을 받고 ACK를 보낸 상태, 동일 포트와 주소에 커넥션이 생성되지 않도록 하는 시간(2MSL time out)을 기다리는 상태
LAST-ACK	2번쨰 FIN을 보내고 ACK를 기다리는 상태
CLOSING	    양쪽이 동시에 닫기로 한 상태&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ecda2bc2-5d1b-452c-91ec-a0801a46cbbf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-F53BF2B0-DFE0-478F-B821-041E45BB65B9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TCP에서 Passive와 Active 개념이 있습니다. Active는 무언가 요청하는 대상을 의미하고 Passive는 요청을 받는 대상을 의미합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-88CE6C67-7039-4E61-8727-07D57B4259F5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-38BFA8FD-F7EC-4685-BF1F-0F26BEF1F08A&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Active Open은 연결 오픈을 요청하는 대상, Passive Open은 연결 오픈 요청을 받는 대상&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D221A944-EAA9-41E5-9521-6266FBA0760B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Avtive Close은 연결 종료를 요청하는 대상, Passive Close은 연결 종료 요청을 받는 대상&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E0752CB2-5990-4442-8995-49DDA4DFD098&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-3CE130D8-943E-46CE-B915-0C45DA6F28CC&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; HTTP/1.1 문제점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-16DC4315-91A1-4497-B5EA-C5943DAC0C60&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; HTTP/1.1은 크게 2가지 문제점을 가집니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a0d506e-c168-4def-9ac6-5b55ccf22be4&quot;&gt;
&lt;pre id=&quot;code_1661666684503&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HOLB: Head Of Line Blocking
RTT: Round Trip Time
Heavy Header&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fdae95ca-e1f1-40d4-93c3-9f49292d63b1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-B1CE0A6E-B337-4005-84CD-3AE7AEC5E290&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ HOLB(Head Of Line Blocking)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-FCF8ECF1-7067-4FD2-A422-81ECA9E87C3E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 HTTP/1.1은 ESTABLISHED를 계속 유지하여 TCP 연결을 최소화합니다. 하지만 해당 상태를 유지하더라도 문제점이 있습니다. 바로 HOLB입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a08591ed-1438-46d5-9e88-725425e58165&quot;&gt;
&lt;pre id=&quot;code_1661666699943&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;setInterval(async () =&amp;gt; {
    await fetch('http://127.0.0.1:5000')
}, 300)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-080D9B4B-752C-46E2-91A2-57CCFF35833E&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1C28BB02-E033-468C-A687-A16B880D82F6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 형태로 300ms마다 서버로 요청을 합니다. 만약 응답하는데 300ms가 더 걸린다면 어떻게 될까요. 예를들어 10개의 요청을 발생했을 때 7번째 응답해야하는 데이터의 크기가 너무커서 지연이 되었다고 가정하겠습니다. 7번째 이후 응답은 7번째 응답이 완료될 때까지 지연됩니다. 왜냐하면 TCP는 클라이언트의 요청을 받고 데이터를 전달하는 과정을 블락킹하기 때문입니다. 블락킹하는 이유는 TCP 자체가 순서보장을 해야하기 때문입니다.3개의 요청은 반드시 요청한 순서대로 응답해야 합니다. 이를 보장하는것이 TCP의 역할입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-C51186DB-1BCC-4490-BCF2-A7F607538268&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ RTT(Round Trip Time)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-77249B4A-09F8-46D2-87D5-693BB3F5759B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;근본적으로 HTTP는 TCP 기반으로 하기 때문에 3 way-handshake, 4 way-handshake로 인한 네트워크 지연은 피할 수 없습니다. Connection: Keep-Alive으로 커넥션을 유지하지만 일정시간 데이터를 주고받지 않으면 연결을 끊고 다시 연결을 수행합니다. 연결상태를 계속 유지할 경우 서버의 입장에서 메모리 문제가 발생할 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-2276FBF6-361C-48EA-85F9-958757E24860&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ Heavy Header&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-6A79DEDB-15EB-4006-B729-8B6486ACB6ED&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 TCP 서버를 연 후 브라우저 및 HTTP 클라이언트 프로그램으로 커넥션하여 데이터를 전송할 때 실제 데이터보다 너무 방대한 헤더를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1C35E78D-D025-4FE4-AF87-1F8E3D1844F2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-04F53325-A0B5-4180-8E83-F22BD0C6DF85&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/1.1은 실제 사용될 데이터보다 반복적으로 헤더를 포함하기 때문에 데이터가 전체적으로 무거워집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ED81B87F-E29C-4543-8B70-6FDD81A1EFCA&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E8A72877-B89A-4D79-9362-72BF53F4B476&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/1.1은 이러한 문제를 해결하기 위해 나름 여러 방법을 고안했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-32E3BAC4-C055-47C3-822C-7F1C0ABCF82C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-B44DF38B-2A33-4241-BAF7-ADE2115C6C0C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Image Spriting, Domain Sharding, Minified CSS/JavaScript, Load Faster, Data URI Scheme&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-00D5228D-62F6-4055-AAD2-358641EE3FF3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-3C75C743-1966-47EB-BCBC-DCD1959B4303&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; HTTP/2.0&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-16782A39-E34F-46B4-9DDE-64AD45D8D856&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/2.0은 HTTP/1.1의 가장 큰 문제인 HOLB와 Heavy Header 문제해결을 목적으로 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-EEDB75F5-32CA-48D4-B6CD-756C00418456&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-28D538BB-8CD1-4A6D-895C-28BE65AF4A88&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;구글은 &lt;/span&gt;&lt;span style=&quot;color: #00afef;&quot;&gt;&lt;b&gt;SPDY 프로토콜&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 구현함으로써 &lt;/span&gt;&lt;span style=&quot;color: #00afef;&quot;&gt;&lt;b&gt;HTTP/2.0&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 구현했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-877D58C1-FD82-4764-9370-398509B6CF54&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-F1BCADA8-9E0C-437C-9100-2F3F2F3118C3&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ Multiplexed Streams&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-C1FC098B-E30B-4A72-937F-706348C3219D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트는 요청 순서에 상관없이 응답을 받더라도 이를 처리할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-86D1CACE-358C-4337-BA65-1A1768B7C2D4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-A905489E-8147-4469-83FD-7311ABB10837&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 사이즈가 큰 패킷을 쪼개어 응답합니다. 간단한 개념으로 사이즈가 큰 응답 메시지를 작은 단위의 여러 프레임으로 쪼개어 응답합니다. 여기서 원본 응답 메시지를 스트림이라고 표현하고 하나의 응답 메시지 스트림을 여러개로 쪼갠 단위를 프레임이라고 합니다. 하나의 스트림은 여러 프레임을 가질 수 있습니다&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-62D4353C-0BBE-4DC8-A267-C1573B531056&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-47FD5B92-7A53-4C07-AAF2-2E7D7E73CA3B&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;응답 결과를 받은 대상은 여러 단위의 프레임을 하나의 메시지로 다시 조립하여 사용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-63413D5A-63C3-437D-AE1E-2783B8F2E890&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D8E9A7F4-4614-45A0-B4B5-59F3185AFCC0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/2.0은 해당 방식을 기반으로 동작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-E442750A-3A52-45B2-9A93-6618958023BF&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ Stream Prioritization&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-1AB42A9D-51BF-46BC-8C0B-3109CC0C32AF&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버는 클라이언트의 여러 요청에 대해 우선순위에 따라 응답 순서를 바꿀 수 있습니다. Multiplexed Streams에서 스트림은 여러 프레임으로 쪼개어 전송을 한다고 했습니다. 이 말은 프레임 전달 순서에 따라 성능 결정을 한다는 의미입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6E3B8CEA-3C47-4C38-BD0E-1FED3E9DBD10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/2.0은 스트림의 종속성과 가중치 조합을 사용하여 클라이언트가 구성한 &lt;/span&gt;&lt;span&gt;&lt;b&gt;우선순위 지정 트리&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 이용하여 통신합니다. 서버는 연결된 클라이언트의 우선순위 지정 트리에 따라 다른 순서로 프레임은 전송하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-B2E13495-20E4-49D7-880A-F9315C6AC275&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ Server Push&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-49D5EBC8-F8EB-48C3-817D-2B3739269FC1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버는 클라이언트의 한번의 요청으로 필요한 리소스 파일을 socket.write()하여 주는것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-D456B05C-9116-4D12-9DF7-55D57E2BC5BB&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ Header Compression&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-73EDB067-DE04-4B22-9EAE-E9D1A0F75952&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP/2.0은 헤더를 HPACK 압축방식을 이용하여 압축합니다. 또한 중복된 값으로 크기가 증가하는 문제를 없애기 위해 static/dynamic header table을 이용하여 중복을 최소화합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-251E5B60-20F7-4278-B784-6BAD3A9148C7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6BB758A9-4532-42AB-93AE-E5E7297A8D6D&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;HTTP/1.1&lt;/b&gt;&lt;/span&gt;&lt;span&gt;과 &lt;/span&gt;&lt;span style=&quot;color: #00afef;&quot;&gt;&lt;b&gt;HTTP/2.0&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 근본적으로 &lt;/span&gt;&lt;span style=&quot;color: #00afef;&quot;&gt;&lt;b&gt;TCP&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 기반으로 동작하기 때문에 handshake 문제를 피할 수 없습니다. 또한 multiplexed streams를 이용하더라도 HOLB 문제를 완벽하게 해결할 수는 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-351F8E3B-6016-4C31-95E5-BA483D6EFB03&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rXGNu/btrKK95yAqK/4oyfg0y2fJrhCDLbeehba0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rXGNu/btrKK95yAqK/4oyfg0y2fJrhCDLbeehba0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rXGNu/btrKK95yAqK/4oyfg0y2fJrhCDLbeehba0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrXGNu%2FbtrKK95yAqK%2F4oyfg0y2fJrhCDLbeehba0%2Fimg.jpg&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;773&quot; height=&quot;437&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-BD41B0D2-A071-42C4-BA79-B57E0A3FA65C&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;SE-3CE130D8-943E-46CE-B915-0C45DA6F28CC&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; &amp;nbsp;&lt;/b&gt;&lt;b&gt;HTTP/3.0&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-5034D217-711E-4CB3-AE6B-1045A3704E71&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff9c23;&quot;&gt;&lt;b&gt;HTTP/3.0&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ff9c23;&quot;&gt;&lt;b&gt;UDP&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기반으로 구현된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ff9c23;&quot;&gt;&lt;b&gt;QUIC 프로토콜&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 이용합니다. 즉, HTTP/3.0은 UDP를 사용합니다. TCP 대신 UDP를 사용하면서 handshake 과정이 없어지기 때문에 네트워크 레이턴시가 상당히 짧아집니다. 하지만 데이터의 보장이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ff9c23;&quot;&gt;&lt;b&gt;100% 확신할 수 없는 프로토콜&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt;입니다. TCP와 UDP 패킷만 까봐도 TCP는 데이터의 신뢰도를 보장하기 위해 엄청나게 많은 정보를 포함하고 있습니다.(여기서 신뢰도란 데이터를 전송할 때 완벽하게 목적지에 도달하는 것을의미) 하지만 UDP는 신뢰도를 보장하지 않기 때문에 패킷이 매우 가볍습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fe0848ab-02c1-4356-9c02-d944b76cfa68&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mSfhl/btrKIqNsGAh/JjnA7ww9vY3qkttu3aGWzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mSfhl/btrKIqNsGAh/JjnA7ww9vY3qkttu3aGWzk/img.png&quot; data-alt=&quot;TCP 패킷(출처:&amp;amp;nbsp; http://www.ktword.co.kr/test/view/view.php?m_temp1=1889&amp;amp;amp;id=1103 )&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mSfhl/btrKIqNsGAh/JjnA7ww9vY3qkttu3aGWzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmSfhl%2FbtrKIqNsGAh%2FJjnA7ww9vY3qkttu3aGWzk%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;518&quot; height=&quot;312&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TCP 패킷(출처:&amp;nbsp; http://www.ktword.co.kr/test/view/view.php?m_temp1=1889&amp;amp;id=1103 )&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d9e49afc-3013-4851-b242-341f2c767b63&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKMwIY/btrKIxFSw67/IXjm4iX0MNNYpKMenblZB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKMwIY/btrKIxFSw67/IXjm4iX0MNNYpKMenblZB0/img.png&quot; data-alt=&quot;UDP 패킷(출처:&amp;amp;nbsp; http://www.ktword.co.kr/test/view/view.php?m_temp1=323&amp;amp;amp;m_search=UDP )&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKMwIY/btrKIxFSw67/IXjm4iX0MNNYpKMenblZB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKMwIY%2FbtrKIxFSw67%2FIXjm4iX0MNNYpKMenblZB0%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;253&quot; height=&quot;135&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;UDP 패킷(출처:&amp;nbsp; http://www.ktword.co.kr/test/view/view.php?m_temp1=323&amp;amp;m_search=UDP )&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3ffe8d67-5629-4a07-ab89-449488e37def&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-D1EA2824-8B81-4BDB-864D-A9252999DFF0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;패킷만 봐도 TCP가 얼마나 복잡한지 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-A43C2A76-4DB1-4471-8D3C-EF8A578BD2DD&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-CAE6CECD-7722-4994-B63C-4248125537A6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 HTTP/3.0을 쓰기 위해서 반드시 HTTPS를 적용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7EBE04F6-C2C9-4A34-85CC-BA3DBFB58B5E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-C5764A0C-24A7-4F54-BE64-D140356A49F6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;필자의 경우 아직 UDP 기반의 HTTP/3.0이 정말 기존의 HTTP를 완전히 대체할 수 있을지는 잘 모르겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-A934C645-7851-4224-BE16-72C76664CCD1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-0C9AC76C-BB2F-45D0-9029-8A30CFFF55E5&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 연결성과 상태유지&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-88452C3D-24C2-468D-9F8D-DC14D8A1E5F1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막으로 HTTP의 연결성 및 상태유지를 다뤄보고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4af9b785-2733-4e2b-9a4c-a2fb2b35facb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;147&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boFw0a/btrKJ4DnJvM/l8zecIHNmBgxOH0Ovi7Hp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boFw0a/btrKJ4DnJvM/l8zecIHNmBgxOH0Ovi7Hp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boFw0a/btrKJ4DnJvM/l8zecIHNmBgxOH0Ovi7Hp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboFw0a%2FbtrKJ4DnJvM%2Fl8zecIHNmBgxOH0Ovi7Hp0%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;674&quot; height=&quot;147&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;147&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3dad5d3e-d966-4d4a-8193-bbffd90d436a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-2E1E587F-DDF3-4B26-9FA1-99CD2AF44ED9&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 연결성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-6235F3C0-9F9B-4489-B9F6-B36F1A15C586&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP는 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;연결지향(Connected oriented)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이다 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;비연결성(Connectionless)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이다 딱 말하기가 힘듭니다. &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;연결지향&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 비연결은 연결 상태를 유지하느냐 유지 하지 않느냐를 의미합니다. &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;연결지향&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 연결을 유지하여 데이터를 주고받는 것을 의미하며 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;비연결&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 데이터를 전송할 때마다 연결을 다시하여 전송합니다. 즉 데이터 전송할 때마다 3 way-handshake를 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E1153956-0BC7-4F7E-BCBA-EEE7C2D68588&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-15B94080-BF97-4D21-B2E7-C610E25EBBCB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기본적으로 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;TCP&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;연결지향&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 맞습니다. 3 way handshake로 연결하여 ESTABLISHED 상태를 만든 후 데이터를 주고 받고 4 way handshake를 이용하여 연결을 종료합니다. ESTABLISHED에선 연결된 상태를 유지합니다. 1:1 연결이 유지된 상태에서 데이터를 주고받을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3EC11811-0C7F-4EE0-BBB8-888CC9559F68&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-D173CD5F-F52F-4FFA-AEDB-9C63E8B335BE&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;HTTP는 초기 모델&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에서 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;비연결성&lt;/b&gt;&lt;/span&gt;&lt;span&gt;으로 만들어 졌습니다. 그러다보니 매번 데이터를 전송할 때마다 3 way handshake가 발생하여 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;네트워크 레이턴시가 증가&lt;/b&gt;&lt;/span&gt;&lt;span&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1F9F4067-6D04-4ED9-8DFA-F3F2AC4CD707&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;시간이 흐르면서 HTTP도 발전해왔고 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;HTTP/1.1&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에선 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;Connection: Keep-Alive&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 이용하여 커넥션을 끊지않고 연결을 일정시간 유지하므로 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;연결지향&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 됩니다. 하지만 시간이 지나면 커넥션이 끊겨 데이터 전송시 다시 연결을 시도하는 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;비연결&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-E84C3D5D-26F4-4E4F-AAE5-0550213CA793&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-13CC3692-5C32-4C55-8E98-F83921ABD7E7&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 상태유지&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-C99E7034-4F1F-47E2-8C3C-2B9AC866D1E0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;상태 유지의 간단한 예 중 하나가 인증입니다. HTTP의 경우 세션을 유지할 때 redis를 사용하여 관리합니다. 그 이유는 클라이언트가 다른 서버로 요청하게 되면 세션을 가지고 있지 않기 때문에 비로그인 상태로 인식하기 때문입니다. 이렇듯이 HTTP는 자체적으로 상태를 가지고 있지 않습니다. 이를 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;무상태 프로토콜(stateless)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이라고 합니다. 만약, A 서버에서 클라이언트의 세션을 가지고 있었는데 A 서버가 재시작되었다면? 세션은 날아가기 때문에 클라이언트는 로그인 상태가 유지되지 않습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-769B1163-4418-4295-BB24-418D965E89AB&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-854193DF-8545-42D0-9574-8BA8D98623E0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP는 자체적으로 상태를 저장할 수 없기 때문에 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;쿠키, 세션&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 그리고 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;JWT&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 이용하여 별도로 클라이언트의 상태를 포함하여 전송하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>컴퓨터 공학(Computer Science &amp;amp; Engineering))/네트워크</category>
      <category>4계층</category>
      <category>7계층</category>
      <category>http</category>
      <category>IP</category>
      <category>OSI</category>
      <category>PORT</category>
      <category>tcp</category>
      <category>udp</category>
      <category>websocket</category>
      <category>네트워크</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/92</guid>
      <comments>https://meongae.tistory.com/92#entry92comment</comments>
      <pubDate>Sun, 28 Aug 2022 15:07:26 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] 개인키와 공개키 그리고 트랜잭션 서명</title>
      <link>https://meongae.tistory.com/91</link>
      <description>&lt;div id=&quot;SE-68f29e1d-c052-414f-9ec8-879ca4f92ac8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-633b0dc8-7f08-4e50-b9bb-46c95dde5683&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 포스트에서는 개인키와 공개키가 생성되는 과정과 트랜잭션을 서명하고 검증하는 방법을 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9967487a-b490-48ca-96c3-010613a93d56&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-87aaac5e-4812-49a7-a7b5-e266be49a201&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 트랜잭션을 서명하는 과정에서 Simple Replay Attack Protection을 위해 EIP-155를 적용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1a8d1a99-e569-4297-91e2-e642b3dd962c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e261e473-685c-495a-a478-806edf18ebf1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;본론을 들어가기 앞서서 선행되어야 하는 개념이 있습니다. 바로 ECC인 타원곡선 암호화와 modular(나머지) 연산 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-18615b81-e35a-4d9b-9fdb-a3d5ed6467c4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-97e3f949-994f-4b08-9e2b-579fddbe3c93&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● ECC(Elliptic Curve Cryptography)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-ae3ddf1a-858c-476c-a414-433d5d3e083c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ECC는 타원 곡선 암호화라고 불리면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;공개키 암호화&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-38faf4e0-9dec-4c0a-9777-bbaf9222787f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-750fd9d0-1796-478e-adfc-bcad59bb4c84&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 정의&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-10f4a28d-5c9a-49c9-b45c-ef954d309f1b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;타원곡선은 다음과 같이 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-64b1af6b-2efd-4e33-bb50-4ef84276425e&quot;&gt;
&lt;div&gt;$$y^2=x^3+ax+b$$&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-98fd9b2d-fa71-4464-ad1b-91583e3cb9ee&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKlKSE/btrKHdnHcQI/3FEWnz1psJDpUyUpCM0Kzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKlKSE/btrKHdnHcQI/3FEWnz1psJDpUyUpCM0Kzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKlKSE/btrKHdnHcQI/3FEWnz1psJDpUyUpCM0Kzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKlKSE%2FbtrKHdnHcQI%2F3FEWnz1psJDpUyUpCM0Kzk%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;409&quot; height=&quot;410&quot; data-origin-width=&quot;409&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-abfc10f4-7ed0-4106-aa5b-0564bcb22aba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;타원곡선 함수&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-69257684-6c1a-41b8-a281-c897aa56c4bd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-23aa0966-7188-4c1a-bbfc-2df80b7178c4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;타원곡선은 x을 중심으로 대칭입니다. 그 이유는 y가 제곱 형태를띄기때문 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-658608e4-8b84-473d-8476-51d8eea2db3a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0b635912-a2f9-4d49-a4fe-ce0d030532cf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;734&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL8lB6/btrKIxlr5OU/BRwdxUH5yzDGkDmp3fsIWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL8lB6/btrKIxlr5OU/BRwdxUH5yzDGkDmp3fsIWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL8lB6/btrKIxlr5OU/BRwdxUH5yzDGkDmp3fsIWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL8lB6%2FbtrKIxlr5OU%2FBRwdxUH5yzDGkDmp3fsIWK%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;773&quot; height=&quot;734&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;734&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-72492127-fcea-4da6-9b21-8873738ece85&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;a href=&quot;https://www.desmos.com/calculator?lang=ko&quot;&gt;https://www.desmos.com/calculator?lang=ko&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a0e786ad-8fda-4697-8ef7-87a67bb5edef&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-41f95635-6a17-442d-8f5d-adaea7de3b9f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 링크에서 a와 b값에 따라 그래프가 어떤 모습을 보여주는지 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5a178c2d-50cd-4106-a6ab-6e18b0fc9f58&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-de39c1a6-a767-4de6-b6f0-9efd36a02e2f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 연산&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-8166b577-d00b-40f9-b23a-8f20eb8852eb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;타원 곡선 암호화인 ECC를 이해하기 위해선 타원 곡선 함수에서 덧셈 연산을 이해해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fa33b402-fc47-4ef7-af77-8e521c15380b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f3123e45-ed04-4002-bc7c-64832f93b2d1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;타원곡선 상에 다음과 같이 2개의 점을 점 P, 점 Q라고 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-029d69b3-1e8a-4603-bdc3-7092ac8153b0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sxkuU/btrKHZ3uXie/8xVV5tn7vOKL0tkpGPkru1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sxkuU/btrKHZ3uXie/8xVV5tn7vOKL0tkpGPkru1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sxkuU/btrKHZ3uXie/8xVV5tn7vOKL0tkpGPkru1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsxkuU%2FbtrKHZ3uXie%2F8xVV5tn7vOKL0tkpGPkru1%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;773&quot; height=&quot;885&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-209f8f1d-7a11-498e-9bfb-10a5eb242cda&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-75321b0f-8a86-4e46-a2cc-27dc72c2fe73&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;점 P와 Q를 지나는 직선과 타원곡선이 만나는 교점을 -R이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aa9da9a5-9766-44fe-b65c-c5aa99ea0efe&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yjVfb/btrKGw2i9Hp/kXgzKvUkfRRbIR7efgzxqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yjVfb/btrKGw2i9Hp/kXgzKvUkfRRbIR7efgzxqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yjVfb/btrKGw2i9Hp/kXgzKvUkfRRbIR7efgzxqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyjVfb%2FbtrKGw2i9Hp%2FkXgzKvUkfRRbIR7efgzxqk%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;773&quot; height=&quot;885&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a020fbc-aff2-41b5-8f2f-088e3d93480d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7ac03415-3e26-47da-9751-60192b570940&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 -R의 X 축으로 대칭된 점을 R이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2fae1793-4660-4bdf-a58f-5f3c436deb52&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AAszZ/btrKJ4Xv5kp/Jb5UeocnrJvOaBOQxfr0Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AAszZ/btrKJ4Xv5kp/Jb5UeocnrJvOaBOQxfr0Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AAszZ/btrKJ4Xv5kp/Jb5UeocnrJvOaBOQxfr0Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAAszZ%2FbtrKJ4Xv5kp%2FJb5UeocnrJvOaBOQxfr0Ck%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;773&quot; height=&quot;885&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-afbc6181-6578-43a1-81c6-072868c80298&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fd69ac29-4632-45ca-9897-491db9baacf3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 점의 좌표를 ECC에서 덧셈 연산으로 표현하면 P + Q = R이라고 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7f5237da-4bd8-471b-9f69-60e0b86040fb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e1a46d8f-f6ab-4bfe-8988-9c6b42cd7de0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 이용하여 곱셈 연산을 덧셈 연산으로 표현할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-27f54bae-273f-4f7a-a672-f24760baf4f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ECC는 덧셈 연산만 가능하다는 점을 꼭 기억해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ab563dc5-ecd4-4cc7-a1bb-329676567c0e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;곱셈은 덧셈의 연속이기 때문에 덧셈으로 바꿔서 해석이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6c9dcb59-b3bd-413d-a50f-13946f355db7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VtNV8/btrKMoOK5wU/OLWQ01dOiqPQpB1Sy0nLk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VtNV8/btrKMoOK5wU/OLWQ01dOiqPQpB1Sy0nLk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VtNV8/btrKMoOK5wU/OLWQ01dOiqPQpB1Sy0nLk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVtNV8%2FbtrKMoOK5wU%2FOLWQ01dOiqPQpB1Sy0nLk0%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;773&quot; height=&quot;885&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c0c82315-7585-452b-b1ab-977a1a704ed7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ba1dd5c6-5421-42cd-a2e7-a1f5f909e853&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;P와 Q를 두 점이 아닌 한 점으로 표현해도 동일하게 P + Q = R을 성립합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0773a9f5-bb63-4eb0-bf6d-5ab01f4788a1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;P와 Q는 같기 때문에 P + Q는 P + P로 표현가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-42b05bb1-d27f-435a-8875-90ecdb63a4da&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c95ee063-094e-454c-ae90-1d5e1cdf0010&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;P + P = R이 됩니다. 이는 2P = R이 됩니다. 해당 그래프에서 R은 2P가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d84d0e33-2551-44e9-a6fd-ce20990bbf1e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-69fd3baa-0cea-4507-95d3-8022e93fb052&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그렇다면 3P는 어떻게 연산이 가능할까요? 바로 앞의 그래프에서 점 P와 점 R(2P)를 지나는 직선을 그립니다. 그리고 만나는 교점을 X축으로 대칭한 위치가 3P가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-48d4be5d-5d9c-4d0c-a594-f7355ecbd976&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dYmExa/btrKJ590ESc/1uKXdvkLZlCnUd0K6tBepK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dYmExa/btrKJ590ESc/1uKXdvkLZlCnUd0K6tBepK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dYmExa/btrKJ590ESc/1uKXdvkLZlCnUd0K6tBepK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdYmExa%2FbtrKJ590ESc%2F1uKXdvkLZlCnUd0K6tBepK%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;773&quot; height=&quot;885&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;885&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bf9f98e3-edda-40cd-83c7-5d64ef26a11c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f518d5cb-40c4-47f8-976b-03ecf4338669&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 핵심은 곱셈은 덧셈의 연속으로 풀 수 있다는 점일 인지하도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-08846094-82da-4296-9065-3b03524aeaf7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1d194ac5-e334-4fbd-90ca-310c2f4fae3f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 수식으로 풀면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-204df076-81eb-4f73-aa26-b5b40aa9597d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1edee0e6-6251-4501-8a57-274dbafd66da&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;P(x1, y1), Q(x2, y2)가 E 상에 존재할 때 R(x3, y3) = P(x1, y1) + Q(x2, y2)가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-04e742ef-61e5-4cc9-a6a7-f6e12f1d8620&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;$$P,\ Q\ \in \ \ E\\ P\ =\ \left(x1,\ y1\right),\ Q\left(x2,\ y2\right)\\ R\ =\ \left(x3,\ y3\right)\ =\ P\ +\ Q$$&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3d20307f-7f29-48e9-acbf-c2333300a0f9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3ab3e528-d127-47f2-b8fb-d605b937aa2f&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;SE-46ff5b88-f2d0-4c54-814e-afbde8887f37&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;☞ P != Q일때(addition)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4643b53e-ccf0-4a06-9594-f01f1088b101&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;$$\lambda \ =\ \frac{y2\ -\ y1}{x2\ -\ x1}$$​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-83fa7174-49bb-47fc-a036-d6a036f20e5b&quot;&gt;
&lt;div&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;$$y3\ =\ \left(x1\ -\ x3\right)\lambda \ -\ y1$$​&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4212609c-95df-4a3e-a1f9-ddf529aa37bc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-9303e498-e46e-45a7-b50f-2f37fe6867c5&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;☞ P == Q일 때(Doubling)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1c61c03a-8055-445d-b91f-735760377a35&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;$$\lambda \ =\ \frac{3\ \cdot \ x1^2\ +\ a}{2\ \cdot \ y1}\left(a는\ y^2\ =\ x^3\ +\ ax\ +\ b에서의\ a이다\right)$$​&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-da83cd92-f69c-41ef-89df-e9dbf800bd9b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;$$x2\ =\ {\lambda }^2\ +\ 2\ \cdot \ x1\\ y2\ =\ \left(x1\ -\ x2\right)\lambda \ -\ y1$$​&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-554f028d-08d0-4796-a6fc-1f5018f432b5&quot;&gt;
&lt;h3 id=&quot;SE-a8348563-6fa4-47e4-86c1-9d8f337194cf&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 모듈러(나머지) 연산&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-19ca22c7-28f6-4047-af43-8c6b472e30fd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모듈러 연산은 나머지연산입니다. 연산자는 mod라고 표기합니다. 코드레벨에선 %으로 대부분 표현합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-84317a77-f730-410a-99a1-d4f3a1bbab17&quot;&gt;
&lt;pre id=&quot;code_1661643565198&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;10 % 3 = 1
10 mod 3 = 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-66e26c48-a745-4704-aa0c-55dff072ade4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7d4549ee-f777-4993-911c-178a7645098c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 음수에 대한 모듈러 연산을 어떻게 해야할까요?&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1249c07a-ded5-4d34-90db-ac57e0efa566&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-da6b4518-d8bd-4bdd-8d52-fb6333c7df60&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모듈러 연산의 특징 중 하나가 피연산자의 값을 주기로 같은 결과값을 가지는 주기성을 띕니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-785beda2-67a1-46b6-95ec-e190e3958453&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6123dc14-4c96-4320-9bac-cdccb437b3b3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661643571198&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-5 mod 3은 다음과 같이 변환가능합니다.
(-5 + 3) mod 3 =&amp;gt; -2 mod 3
-5 mod 3 = -2 mod 3 이 두식의 값은 같습니다. 

(-2 + 3) mod 3 = 1 mod 3 = 1&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-7eebffda-43b6-43a7-8cbe-d278db88c40c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-040cc9c0-3409-4e7d-825e-a757cf3ff6fa&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 갈루아 필드에서 타원 곡선(Elliptic Curves Over GF(p))&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e2965236-c1fa-4b39-acca-8383c386139e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;갈루아 필드는 유한체를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-06bae62a-e395-4ceb-b0d7-80630d4f0173&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2a738053-12f9-4ce6-a9bb-87568a2b6e0f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;유한한 좌표를 가지는 공간을 의미하며 이는 modular 연산을 이용합니다. mod p를 수행합니다. p는 소수로 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6bbcac3f-f6dc-497f-ab7c-2b9ecfc49b5f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s3SEQ/btrKGpa1Uug/z97VAfOKcYYnGQPrBLkKyK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s3SEQ/btrKGpa1Uug/z97VAfOKcYYnGQPrBLkKyK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s3SEQ/btrKGpa1Uug/z97VAfOKcYYnGQPrBLkKyK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/s3SEQ/btrKGpa1Uug/z97VAfOKcYYnGQPrBLkKyK/img.gif&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;773&quot; height=&quot;551&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-531bd7ec-034b-4c28-bedd-aacdb338507f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4fe173ac-a960-4cb5-b5e8-1fe9cb3a4122&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;갈루아 필드는 다음과 같이 정의할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1dd15000-1364-4cde-818e-8def863dee2c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdBhXZ/btrKJ68TjWn/tpz1GJOfYIkK1i6w1TrBl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdBhXZ/btrKJ68TjWn/tpz1GJOfYIkK1i6w1TrBl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdBhXZ/btrKJ68TjWn/tpz1GJOfYIkK1i6w1TrBl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdBhXZ%2FbtrKJ68TjWn%2Ftpz1GJOfYIkK1i6w1TrBl1%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;641&quot; height=&quot;94&quot; data-origin-width=&quot;641&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-db295eae-0c94-49bb-b947-ed06a38458de&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6d377daf-3c29-4742-a67c-516d395b8eaf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7b2179eb-dcc4-4bdd-9011-2b898db291a0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음은 갈루아 필드의 예입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;$$y^2=x^3+x\ over\ {Z}_{23}\ (p=23)$$​&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;SE-8ad71661-3dcc-4971-a51b-11a26b5c5ebb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;414&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eoKadl/btrKHvn0T1P/rsXwwO3JGrBP75oEOK1ctK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eoKadl/btrKHvn0T1P/rsXwwO3JGrBP75oEOK1ctK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eoKadl/btrKHvn0T1P/rsXwwO3JGrBP75oEOK1ctK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeoKadl%2FbtrKHvn0T1P%2FrsXwwO3JGrBP75oEOK1ctK%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;414&quot; height=&quot;428&quot; data-origin-width=&quot;414&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4c20acfe-0193-46bc-bd1d-a5f117f8ee70&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1608758b-7b38-408c-accb-86f5f970172c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-35641814-1e37-4cbd-8f3e-6e6cd4f74eb6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 x가 9라면, (9^3 + 9) mod 23 = 2가 됩니다. 이는 (5 * 5) mod 9 = 2로 표현이 가능하며 y는 5가 됩니다. 즉 x가 9일 때 y는 5가 나옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4c662e78-34a9-4d7d-8644-b019a2634a13&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f771ec3a-fe2c-4dfc-a7c6-0d1ae6b995f2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 p가 커진다면 y는 쉽게 찾기 힘듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-30fd4cf4-e9dc-4992-85a4-d96bbca8d52e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-0f7c7d79-36c6-44c2-94c1-f2f755d37132&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; privatekey, publickey&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-90ebf899-6986-4a4b-b9d8-a212a2565b62&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ECC는 퍼블릭키를 생성하기 위해 먼저 개인키(pk)를 랜덤하게 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2d58046f-7144-4b72-9532-b780eaeed9a0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;퍼블릭키(pub) = pk * G(x0, y0) (G는 이미 알려져 있음 이를 베이스 포인트라고도 부름)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e6cd1ee6-d059-4de4-9849-96564981a008&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-48bbe11c-11a0-477d-8910-696d493b848d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, 퍼블릭키는 G(x0, y0)을 pk번 더합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-66b618a0-8d9c-44de-b835-5cd31c742f2d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b7338eb7-2d22-4713-a0d9-67c8e3207d2f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 이런 의문이 들 수 있습니다. G는 이미 공개가 되어있고 공개키는 공개가 되어있으면 개인키(pk)를 찾을 수 있는거 아닌가?하는 생각이 들 수 있는데 ECC에서 G와 공개키를 알 수 있다고 pk를 찾는건 매우 어렵습니다. 이를 ECDLP라고 하며 이러한 특징 때문에 ECC를 공개키 암호기술로 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-df5c61d0-4564-4858-a133-94915002dd4c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ec517abd-0ee1-460c-8ed2-27bdb67e6bf8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;한 가지 예시를 들어보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2eaafe9b-229b-44ab-bb8a-d870e8b67ea3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-aa44794a-18cb-4209-bc38-249184a98af3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;갈루아 필드가 다음과 같이 정의될 때, G = (2, 7)일때 2G를 계산해 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-633061f9-769e-44c0-8d24-defa188d5481&quot;&gt;$$y^2\ =\ x^3\ +\ x\ +\ 6\ over\ {Z}_{11}$$&lt;/div&gt;
&lt;div id=&quot;SE-46607947-fdb0-4539-b936-839906bc667a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a2f4798a-a124-4d87-9955-18590edc1303&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 2G는 G + G이므로 앞에서 P == Q(doubling) 공식을 대입하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-df74fbd3-a566-4ca9-beee-cacd672fcba3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;$$x1\ =\ 2,\ \ y1\ =7\\ \lambda \ =\ \frac{3x1^2\ +\ a}{2y1}\ =\ \frac{3\ \cdot \ 2^{2\ }+1}{2\ \cdot \ 7}\ =\ \frac{13}{14}$$​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dbb31fda-661f-49ad-adc7-db876c3b924a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0e9f6d65-fe42-491e-9e28-49b5d6c6fefb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 람다 결과인 13/14를 분자 분모를 각각 mod11을 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c2860f91-014e-4309-9398-76bf08b1ce41&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;$$2\ \cdot \ {3}^{-1}$$​&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-87bd6e9a-3190-40c6-8a7f-efe05f9939c9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4c3b0fb9-ea32-4a1f-887d-d2a75de6f04b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 3^-1을 mod 11 연산을 하면 4가 나옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8fb8f062-6424-4375-9f22-8c196e74ec0b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;$$\lambda \ =\ 2\ \cdot \ 4\ mod\ 11=8\ mod\ 11\\ x2\ =\ \lambda \ -\ 2x1\ =\ 8^2\ -\ 2\ \cdot \ 2\ =\ 5\ mod\ 11\\ y2\ =\ \left(x1\ -\ x2\right)\lambda \ -\ y1\ =\ \left(2\ -5\right)\ \cdot \ 8\ -7\ =\ 2\ mod\ 11$$​&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7cc0830b-206c-4fa3-9b55-e878156cc541&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ddf43ab3-acfd-4fbd-8ffa-ad16c491aa79&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 G, 2G, 3G, 4G, ... KG(K는 임의의 양의정수)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c16a305b-d698-4204-93c3-43ea1886264f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-25704a16-c262-4981-8377-862865afe67d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;pk(개인키) * G(베이스 포인트) = pub(공개키)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e2bb52c4-2837-43dd-8028-fb15f242c41a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;G=(2, 7), 2G = (5, 2), 3G = (8, 3)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-26d3be0f-a489-468f-b33f-ff075fc6c07e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4G = (10, 2), 5G = (3, 6), 6G = (7, 9)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-49d8f41a-d416-42bb-be1b-8e5a8157c68b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;7G = (7, 2), 8G = (3, 5), 9G = (10, 9)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a0b5a4a3-8e59-4375-a7e4-7b07ace91ae4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-a8d40918-e382-4545-a265-c6a3b587ef82&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 이더리움의 개인키 공개키&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-9919d03f-4ce0-444a-b447-f4251362db2d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션을 만들기 위해선 트랜잭션을 서명할 개인키가 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b0ffbaa4-cee7-4975-90c6-3930728901df&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움은 개인키 - 공개키 - 주소 순서로 키와 주소를 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4910bde9-2927-42db-9863-41c05d63dde9&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 개인키 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-7606289f-7456-4d7e-b8e4-d5a9b6be54b6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개인키는 1 ~ n-1까지 정수 중 하나의 랜덤값 입니다. 여기서 n은 secp256k1 타원곡선에서 1.157920892373162e+77으로 정의됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f4378bb6-7155-46c7-90f0-10e5008dea5a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;secp256k1 타원 곡선 함수는 a=0, b=7로 정의되며 G=02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798 입니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c70833b8-6f3f-4bac-8beb-085969f4ba49&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 유한군 소수값인 p는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F으로 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8489bb69-f6ac-41ce-b707-481edcd5d59c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a = 0&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;b = 7&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;유한군 p값 = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;G=02 79BE667E F9DCBBAC 55A06295 CE870B07 029BFCDB 2DCE28D9 59F2815B 16F81798&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-98d61ccd-88c0-4e61-955f-5da70f699d50&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6392aa37-600c-40b2-81c7-f2ab7481bc0e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개인키는 1 ~ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140 까지의 범위를 가집니다. 해당 범위를 넘으면 올바르지 않은 키라고 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6f861318-5879-44c2-ba6e-8d0fa8cb102f&quot;&gt;
&lt;pre id=&quot;code_1661643324055&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { Wallet } = require('ethers');

async function main() {
  const private = 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140';
  const wallet = new Wallet(private);
  console.log(wallet)
}

main()

/*
Wallet {
  _isSigner: true,
  _signingKey: [Function (anonymous)],
  _mnemonic: [Function (anonymous)],
  address: '0x80C0dbf239224071c59dD8970ab9d542E3414aB2',
  provider: null
}
*/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-934f8bb9-19fd-4293-b328-fd538d4ee674&quot;&gt;
&lt;pre id=&quot;code_1661643324056&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { Wallet } = require('ethers');


async function main() {
  const private = 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141';
  const wallet = new Wallet(private);
  console.log(wallet)
}

main()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-749e6ad2-f510-41e0-8c9a-202ccb56edbb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5mRCT/btrKHuo5Iqn/pRtHWduS1WkaFTmUtapDh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5mRCT/btrKHuo5Iqn/pRtHWduS1WkaFTmUtapDh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5mRCT/btrKHuo5Iqn/pRtHWduS1WkaFTmUtapDh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5mRCT%2FbtrKHuo5Iqn%2FpRtHWduS1WkaFTmUtapDh0%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;773&quot; height=&quot;195&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0d354008-1954-443d-acda-55aea177a50a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-60b28e30-9028-4f29-b952-e905a160291d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ECC는 개인키를 구한 후 공개키를 구하지만 RSA는 공개키를 구한 후 개인키를 구합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c3512479-a2f7-4264-b6f5-69e54242d7e7&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 공개키&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-d8d98207-f4cb-421e-a650-feba8f7134be&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;공개키는 개인키로 생성합니다. 개인키와 이더리움에서 정한 기준점 G를 곱합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3a792868-9303-40e2-8c4e-466018ef0a97&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;공개키 = 개인키 * G&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c8ca3be7-a4c6-4c71-a709-2eb6dfe341de&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0325c084-1b26-4d0f-ac9c-b6ab55851854&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;공개키는 ECC의 덧셈 연산을 통해서 연산합니다. 기준점 G를 개인키만큼 더합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-92e004b2-3fd7-4252-aa3b-5bcae76d0f99&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 주소&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-64884069-cfba-4b73-95ab-f57b99f91ab8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주소는 공개키를 keccak-256 해싱 결과의 마지막 20바이트입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-2e3603c3-e38a-47d0-8295-932a6c15dcbd&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 트랜잭션 서명과 검증&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-d09ba85a-3e60-46bc-a16c-fd2b7d8b86b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움은 트랜잭션 서명을 위해 ECC를 이용한 디지털 서명을 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4128d27d-f25c-410b-a86d-fbff493c67b0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-477dfa4a-def6-40e3-b09e-a5b5671a3665&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 ECDSA라고 합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;ECDSA&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 타원 곡선 디지털 서명 알고리즘입니다. ECDSA에서 secp256k1을 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6ee8641d-087b-44c8-a67c-a70ec366ae32&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5d571da0-bae2-4479-9f20-98cc3dcf307f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션 서명을 위해 r, s, v를 트랜잭션에 포함해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7bd98126-14c3-4182-8275-c9720fe50628&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b7e5d817-cf80-4a43-8ff0-96f3033ed578&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;r과 s는 서명입니다. v는 공개키를 복구하는 키 입니다. 이더리움 트랜잭션을 서명할 때 공개키를 포함하지 않고 공개키를 복구할 수 있도록 공개키 복구키인 v를 포함합니다&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-77b54cad-cd08-492c-a7a3-d48eb1ff63b6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-344a14d9-e7b4-4908-9f43-e28f3d53087c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 서명 r 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-108d7410-adfa-4910-ae6d-064a2000a4c8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션 서명을 위해 r을 만드는 과정은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f9dd16ef-a8bd-40c4-b479-bef7d3ba0253&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3f011ef1-5c69-4ad5-bd87-03c0281d0d54&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개인키를 만든 것 처럼 1 ~ n-1 난수를 생성합니다. 여기서 생성된 난수를 k라고 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a52e76ee-e8fe-49cd-8c61-1c1196a7ecc9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개인키의 경우 한 번 생성되면 계속 사용하지만 서명 r은 트랜잭션을 서명할 때마다 새로 생성합니다. ECC식인 P = k * G를 통해 점 P의 좌표를 구합니다. 이때 x 좌표가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;서명 r&lt;/b&gt;&lt;/span&gt;&lt;span&gt;값이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-190a3b58-2009-40d8-b548-330ff4f688ae&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-5bd70353-9379-4723-b244-a1ff790b93d8&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 서명 s 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-5fcbeea8-464e-41d1-a4a0-04af72654e85&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;s는 서명 r을 생성하기 위해 만든 난수 k를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3b235898-c69b-4fe8-a01d-8ef20eb969a4&quot;&gt;$$s\ \ =\ k^{-1}\ \left(z\ +\ r\ \cdot \ p\right)\ mod\ n$$&lt;/div&gt;
&lt;div id=&quot;SE-557e34e7-308b-4801-8d5d-9ca019f5d6d1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ab4ddedb-3247-4ee5-9515-c2b8ba47d864&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;z는 트랜잭션 정보를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ff9300;&quot;&gt;&lt;b&gt;RLP 인코딩&lt;/b&gt;&lt;/span&gt;&lt;span&gt;한 값입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6447b44a-f4ce-4ce7-b72e-b0382d7c732d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;r은 서명 r입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0975705c-68a9-4f72-9429-0716d008ee7c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;p는 개인키입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e40fe6e2-f26e-410d-b860-89d51626df23&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1d6ec51d-11e3-49b5-b6fc-b0b659d4b436&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약, 이때 서명 s가 0이 나오면 k를 새롭게 생성하고 다시 계산합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9d56baf5-308f-448f-a86b-bb7011655dda&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-d296ca5e-ac6e-4219-8788-7faaf6b59e8c&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ (RLP 인코딩 시 포함하는 트랜잭션 정보는 다음과 같습니다.)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-f8b96a57-f4df-496b-8fb2-774bd547e0a8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nonce, gasprice, startgas, to, value, data,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;chainID&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, 0, 0&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f6aeca06-1095-437e-afc4-5c293048c42f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;EIP-155&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;simple replay attack protection&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;chainID&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 포함하여 인코딩하는 것을 권장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2e6c5a20-dcd5-4c33-a1af-7f77776784a2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-21933b71-1c0f-4429-9615-21fa646982b8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-155&quot;&gt;https://eips.ethereum.org/EIPS/eip-155&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661643324059&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;EIP-155: Simple replay attack protection&quot; data-og-description=&quot; &quot; data-og-host=&quot;eips.ethereum.org&quot; data-og-source-url=&quot;https://eips.ethereum.org/EIPS/eip-155&quot; data-og-url=&quot;https://eips.ethereum.org/EIPS/eip-155&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-155&quot; data-source-url=&quot;https://eips.ethereum.org/EIPS/eip-155&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('&amp;quot;&amp;quot;');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;EIP-155: Simple replay attack protection&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;eips.ethereum.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d88973a9-51dd-47ef-82d6-1b85ba643636&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-670170a6-7f00-406d-835d-6f867aec2cca&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 공개키 복구키 v 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-dfc7bbd9-be61-417a-9db6-47cc7975f930&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움에서는 트랜잭션에 공개키를 추가하지 않습니다. v라는 값을 이용하여 공개키를 복구 할 수 있도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-97705a7c-af03-4f1e-9858-44ba0372df9b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0ec779bb-45f6-4d87-b7e6-83a3ab2718ca&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;EIP-155에서 v는 다음과 같이 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-713d0f1e-8874-4011-9837-63cff4e97b32&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;v = CHAIN_ID * 2 + 35 또는 v = CHAIN_ID * 2 + 36&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-38f56b5d-168d-4513-92a0-b3dc351ce599&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, 메인넷 기준으로 37 또는 38이 나옵니다. 또한 0 + 27 또는 1 + 27을 사용하기도 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a96b3f48-1c8b-4654-88a6-1d698a1471a6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-798d7e1c-78a3-4196-bc86-97ec58c00a10&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 전송&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-f6ed565c-5834-44a4-a481-7eeaea44739a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서명 s, 서명 r, 복구키 v를 트랜잭션에 포함한 후 RLP 인코딩하여 전송합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-65d4ad40-a1e9-4d56-a795-7282c87c1141&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-16f784f6-89a3-4136-ae0e-f562d2308373&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 검증&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-956e7b95-b658-4137-9402-34073ae73893&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션 검증은 별도의 식이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4127d1c1-78dd-4ff0-b57c-7c5540bc96f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;트랜잭션 검증 식 = U1 * G + U2 * public key&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5bedf47e-3183-4565-a737-36f6fbe1679b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1a9f0bf1-b9f7-424c-bf81-5efdb0a10f9f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;w = s^-1 mod n (s = s서명)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-97544f0e-3071-4c85-8551-2e03e9895886&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;U1 = z * w mod n (z = 트랜잭션 RLP 인코딩)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-43607360-a14d-43e6-9580-11646adc6c84&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;U2 = r * w mod n (r = r서명)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e338d81d-fefc-4afe-940f-5f3641bc37e7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1e1d959a-072d-4b2f-bd9c-2846801e5c64&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;U1과 U2는 서명 s와 서명 r을 이용하여 알 수 있습니다. public key는 복구키인 v를 이용하여 복구할 수 있습니다. 복구키 v는 서명 r과 서명 s값만 가지고 공개키를 추출할 수 있도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-405e0b55-9c55-469f-aa37-12fdfaf27796&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-92930442-5c53-4384-895a-589a522a5994&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;solidity에서는 ecrecover() 함수를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-73e0e306-96f9-435e-82c9-4b1f00b3c1b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b7acf8b3-d78b-4b6d-bfd5-4ed127cb9c91&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;트랜잭션 검증식&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 타원곡선의 연산으로 타원곡선 위의 점이 나오게 되며 해당점의 x 좌표값과 트랜잭션에 포함된 서명 r값이 같으면 해당 트랜잭션을 유효하다고 판단합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-d86332c9-ce37-48a0-af20-bffe06c74bd0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;참고자료:&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-78bde145-0704-459e-9393-1a3ccb278785&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;http://wiki.hash.kr/index.php/%ED%83%80%EC%9B%90%EA%B3%A1%EC%84%A0_%EB%94%94%EC%A7%80%ED%84%B8%EC%84%9C%EB%AA%85_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&quot;&gt;http://wiki.hash.kr/index.php/%ED%83%80%EC%9B%90%EA%B3%A1%EC%84%A0_%EB%94%94%EC%A7%80%ED%84%B8%EC%84%9C%EB%AA%85_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2f1da5d2-6025-4f24-b10b-9053f08ed78d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cb8efb79-1584-4f90-853b-b836c5fd02ec&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://eips.ethereum.org/EIPS/eip-155&quot;&gt;https://eips.ethereum.org/EIPS/eip-155&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b4ad484e-8e02-429d-9bfd-7392d814cdcc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f6fd9480-345b-4a6b-8b96-8796e33c03a0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://steemit.com/kr/@icoreport/key-2-ecc&quot;&gt;https://steemit.com/kr/@icoreport/key-2-ecc&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-335d7a4e-a6fe-4c9f-b088-7aa20d5d4e84&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-72749de5-529a-49eb-b255-9d14edd0e9d7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래프 생성도구: &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2d600607-739f-43b6-941f-343d8ad9dd87&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://www.desmos.com/calculator?lang=ko&quot;&gt;https://www.desmos.com/calculator?lang=ko&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/91</guid>
      <comments>https://meongae.tistory.com/91#entry91comment</comments>
      <pubDate>Sun, 28 Aug 2022 08:46:00 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] RLP 인코딩</title>
      <link>https://meongae.tistory.com/90</link>
      <description>&lt;div id=&quot;SE-979665a9-049f-4ce4-a3c6-2e67ebeaf318&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-520ea333-3a13-470d-8737-378b78d8a421&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP(Recursive Length Prefix) 인코딩은 임의의 길이를 가진 문자열과 배열을 인코딩하는 방법입니다. RLP 인코딩은 인코딩 된 값에 길이 정보를 포함합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-260e4445-ec63-47d3-861e-17f55d175c85&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-31233861-8f63-4e1e-8cdd-8cada718bfc9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP 인코딩은 아스키 코드를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-845ea2c8-b9c2-4fd3-afb5-94809e5fee7b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ec5cab7a-f645-41f9-a8c3-2b9d39e639be&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LIHJj/btrKHZoUWPb/biTQCFs6n2iuBDBOCKK80k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LIHJj/btrKHZoUWPb/biTQCFs6n2iuBDBOCKK80k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LIHJj/btrKHZoUWPb/biTQCFs6n2iuBDBOCKK80k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLIHJj%2FbtrKHZoUWPb%2FbiTQCFs6n2iuBDBOCKK80k%2Fimg.jpg&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;426&quot; height=&quot;760&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;760&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4a1b3ed9-95c5-4d1b-9001-59fa06c363f5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1a9c457d-15fd-462f-b7b5-adf4844d4818&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-543144ba-6d1a-4cce-bf59-d48743ad8e25&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● RLP 인코딩&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-da785312-9613-4fb9-8753-1e3c492deb2a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP 인코딩은 5가지 케이스가 있습니다. RLP는 아스키 코드를 절대적으로 참조하여 인코딩을 수행합니다. RLP 인코딩은 아스키 코드표 1~127을 제외한 문자는 취급하지 않습니다. 예를들면 한국어, 일본어, 일부 특수문자 등&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7750c6d9-efff-442c-8e57-3c0477f87c6d&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;SE-8b62ba19-72b2-4239-96a8-bca96a45b2e0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 첫 번째 케이스 - 단일 바이트일 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-5f4b66e1-2046-470d-b2ce-dbdcb24998d3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 케이스는 하나의 바이트만 존재할 때 입니다. 즉, 문자 하나만 존재할 때 해당 바이트에 해당하는 아스키코드 값을 그대로 사용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9e27831d-f133-48c8-b683-ef459175944b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cdfa35b9-9147-462e-9d77-b9937ee1d9b2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 때 해당 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;바이트의 범위&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;0x01 ~ 0x7f&lt;/b&gt;&lt;/span&gt;&lt;span&gt;(1 ~ 127)입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c13f4327-7b62-45ad-880b-92719acb0fb9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;0x12와 0x7f를 인코딩한다고 가정하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-32a8ac18-2a05-4571-a112-4a11109f491d&quot;&gt;
&lt;pre id=&quot;code_1661642358806&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RLP(0x12) = 0x12
RLP(0x7f) = 0x7f&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3627fd86-36e8-477a-9351-df108efd2ae3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a8a283dd-3305-4d9f-a8b5-67834f8c5a76&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a를 인코딩한다고 하면, a를 아스키 코드에서 hex값을 찾습니다. a는 97이며 0x61입니다. 범위가 0x01 ~ 0x7f이므로 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;RLP(a) = 0x61&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-54c7db6e-e083-41f7-af24-2c9002caac00&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-93f747a3-b7b7-446f-a633-105ad5c509eb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff9300;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;RLP 인코딩에서 유일하게 prefix가 붙지않는 케이스입니다.&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e84b2555-6fad-4ab1-81a5-628d1566c03a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-96ca78a3-fb52-415f-97ea-4ae5a0638d00&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 네 가지 케이스의 경우는 길이를 포함한 정보를 prefix로 붙입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d255b714-1b29-4264-ad0e-f7b8cbdc9617&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-ab72d619-c722-45f5-9e78-a6ef45149638&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 두 번째 케이스 - 문자열의 길이가 0 ~ 55 바이트(Byte)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-1d3e495c-a483-401a-878e-85fd17fbd162&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 케이스는&lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt; 0x80&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;prefix&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 사용합니다. 즉, 0x80을 시작으로 인코딩 값을 이어붙입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;SE-a8064802-f2dc-4c96-8df9-d4673c4e4dc9&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;▶ 0x80에 문자열의 길이를 더한 후 아스키 코드표를 참조한 문자열값을 이어 붙입니다.&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-129ba8f6-df99-4f35-9fad-7fbee15c96fc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 abc를 RLP 인코딩 한다면 &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5608be5e-8e4b-44f8-8a70-c173c6126f31&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;a = 0x61(97)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-771a0dc8-3411-4ce1-b297-c93b61c313a1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;b = 0x62(98)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-92b5f094-f98f-4209-a805-6a0a13aa32af&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;c = 0x63(99)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ed9e2fe0-5741-46f3-a5c8-8a6db27e9019&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-90cd4f8f-87e6-41ee-b139-eea291470519&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문자열의 길이 = 3&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e69d7f6b-3624-410a-978f-898a4b469f01&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;prefix = 0x80 + 0x03 = &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0x83&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e8213827-f802-4e24-95f3-b9ee53342786&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1676dad8-f162-452d-90a5-11f0affdb319&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP(&quot;abc&quot;) = &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0x83&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 61 62 63&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a341ca6a-754f-4265-a4eb-a75b0ed014d7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-9868dcd2-1664-468d-8bb4-3f5899df9d7e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 세 번째 케이스 - 문자열의 길이가 55 바이트(byte) 초과&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-8f071ded-4530-42bd-8cc8-5b992bfc4a80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 케이스는 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xb7&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;prefix&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 사용합니다. 즉, 0xb7을 시작으로 인코딩 값을 이어붙입니다. 왜 하필 0xb7일까?&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e3435958-eea6-40e9-91e9-786fe1e817ec&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;0x80에서 55(0x37)문자가 되었을 때 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0x80 + 0x37 = 0xb7&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 나옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e4189418-cac7-4915-bf8a-7492c5312bb3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-6249ef9f-f453-4afc-bd44-76f37045c9c7&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;▶ &lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xb7&lt;/b&gt;&lt;/span&gt;에 문자열 길이의 바이트값을 더한 후, 길이를 이어 붙입니다. 그리고 아스키 코드표를 참조한 문자열값을이어 붙입니다.&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-50189af4-3b28-49ad-a22e-901dfc2dcd78&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약, a*1000을 인코딩한다면,&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fda2af99-ee58-42ce-b9bf-d576800d1a6a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;a = 0x61(97)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fe6c294b-70e4-4719-a963-5fa9f6143e25&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7e03ba64-25a5-4007-bf49-9dcf225f18df&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문자열의 길이 = 1000 =&amp;gt; 11(0x03) 11101000(0xc8)(바이트 단위로 끊는다) =&amp;gt; 2&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cda944a9-d1b6-4f5f-a2f0-87bc3c619e55&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;prefix = &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;&amp;lt;0xb7 + 0x02&amp;gt; &amp;lt;0x03&amp;gt; &amp;lt;0xc8&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-87c1c22c-951c-4d8c-bc4a-3f4ecbc1123a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP(&quot;a&quot;*1000) = &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xb9&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;03 c8&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 616161616...&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-be854c34-6262-47bc-b97d-c8576fabd1ef&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b1906ab6-9351-4c83-af6a-8b89a08c85f8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 케이스에서 prefix는 0xbf까지 사용되며 최대 문자열길이는 (2^64) - 1까지 됩니다. 0xbf면 8바이트만큼 문자열 길이를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2bbe17c7-835e-434f-8c60-3e793851ffbe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-19cf2dfb-c472-4fdb-8f56-51d15740f265&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xbf&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;ff ff ff ff ff ff ff ff &lt;/span&gt;&lt;span&gt;문자열 인코딩값&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1ceeef85-c227-4d49-8fe1-4ae2ea2e66de&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-5b21a907-21d2-4970-8c04-bd972174917b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 네 번째 케이스 - 배열의 모든 아이템들의 RLP 인코딩 된 값들의 길이가 55보다 작을 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-b27ca9aa-456a-42e0-a177-66b037b3ec32&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 케이스는 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xc0&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;prefix&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 사용합니다. 즉, 0xc0을 시작으로 인코딩 값을 이어붙입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-941ad6c8-92d8-4fe4-a60f-084038598a35&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-99b21e7c-2757-475f-91cc-f145920d4627&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;prefix의 범위는 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xc1 ~ 0xf7&lt;/b&gt;&lt;/span&gt;&lt;span&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;SE-c4f44788-5ac1-4e86-ae23-3c69b98e60a9&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;▶ 배열의 모든 아이템들이 RLP 인코딩된 값의 길이를 더하고 각각의 요소를 인코딩 한 요소를 이어 붙입니다.&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-761c4a9d-a1a8-471d-8df9-e86e44daa9b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;[&quot;ab&quot;]을 인코딩하면&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-509c26cf-5687-4b8a-be1b-cd8dc9b7dccf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저, ab를 인코딩 합니다. RLP(&quot;ab&quot;) = &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0x82&lt;/b&gt;&lt;/span&gt;&lt;span&gt;6162&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-081221bb-5b5b-401d-8348-abef8524bcb7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2635bce4-fd90-4df7-8188-4a11fcf8f5af&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인코딩된 값의 길이 = 3 = 0x03&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bcc99b29-304f-4f54-aa8d-c535f41db9ea&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b6bb42e9-7b7d-4bd9-b3f6-d5358216f25f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;prefix = 0xc0 + 0x03 = 0xc3&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-27dd1d64-242b-41b9-81c8-5d942c8379b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP([&quot;ab&quot;]) = 0xc3826162&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-36b46990-2405-48e4-b29d-08ff4bfa227a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f2acfee9-088c-4649-b2d1-2eca5fdf4b92&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;[&quot;ab&quot;, &quot;cd&quot;] 을 인코딩하면&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a62f7f28-478f-48e8-86a0-d3ed7a208476&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 &quot;ab&quot;와 &quot;cd&quot;를 각각 RLP 인코딩합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8a897a6d-ce1b-4fa0-8208-5cdb7bee9eb6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5c2a2016-be2d-484e-8614-32b41b8b0b5c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ab = 0x82 0x61 0x62 = 3자리&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7976f48c-c290-41bd-82da-5037e8ea6793&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;cd = 0x82 0x63 0x64 = 3자리&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-149ad636-5087-44ac-a21a-1933acaedb88&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cb8c4e97-c937-4d04-8a91-b549dddb3db0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배열 요소의 인코딩 결과 길이 = 6 = 0x06&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b3293f4b-9422-4fa6-860f-ce908e50844b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a3f60281-0b05-4007-ab45-4dd9031974ef&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;prefix = 0xc0 + 0x06&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6a2a33f6-2c6a-46f5-ba5f-b8af3505d99e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP([&quot;ab&quot;, &quot;cd&quot;]) = 0xc6 826162 826364&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ba8f29ae-0548-4813-9fb1-0634717befad&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-d7cfdb3c-46af-4c4c-a537-10c1dd23beae&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 다섯 번째 케이스 - 배열의 모든 아이템이 RLP 인코딩 된 값들의 길이가 55보다 클 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-1d93663d-c5f3-49a2-8a6c-5e05f33432e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 케이스는 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xf7&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;prefix&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 사용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5681358d-c725-4be3-abc8-d14f255a183e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1133f65e-1871-47fd-80c6-7556f4538b01&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;prefix의 범위는 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xf8 ~ 0xff&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3ab4ebd7-d3a6-48c9-9afb-e62773448117&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-e7cb69ac-6fe1-4bbc-8487-cbaeee63e0ba&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;▶ prefix에 배열 요소들의 RLP 인코딩 값들의 길이를 표현한 값의 길이를 더하고 아스키 코드값으로 변환하여 붙입니다 (설명이 개떡같죠? 아래의 인코딩 예시를 보면 이해하기 어렵지 않습니다. 세 번째 케이스와 유사한 형태).&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-6b69ff2b-ecdb-441e-a7b1-7a2fdd06a755&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;[&quot;a&quot; * 50, &quot;a&quot; * 50]을 인코딩하면&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-253a0594-cbbf-4423-892d-65d2af39cfb0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저 &quot;a&quot; * 50을 인코딩 합니다. =&amp;gt; 해당 인코딩은 문자열이기 때문에 길이에 따라 2, 3규칙을 적용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b9221b6d-0420-4dfc-976a-dcf8f170ab9d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c9b86418-fa67-4d8a-95fe-ca0e3afd887f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&quot;a&quot; * 50 = 0x80 + 0x32(50의 16진수) = 0xb2 61(50개)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-50cee560-2b77-4ff1-9d6a-4b50335abc11&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&quot;a&quot; * 50 = 0x80 + 0x32(50의 16진수) = 0xb2 61(50개)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f7ea586a-51df-4ae5-a427-af750757bf4f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bfd6652d-a962-4264-bed9-387515c43f40&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;길이 = 0xb2 61(50개) 0xb2 61(50개) = 102(0x66)자리&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d1f608cc-5bd0-4de2-9a98-6c2a31960a5c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;102는 1바이트이며 0x66입니다&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8b2b1f3c-9fe6-4c48-8d1b-6ffad8afd111&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-69cba6ef-6d77-4793-889e-7861dde59caa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;prefix = 0xf7 + 1 + &quot;f&quot; = 0xf8f&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2681df7e-f816-45c2-b08b-f252cd88ba08&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP([&quot;a&quot; * 50, &quot;a&quot; * 50]) = &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xf8&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;0x66&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;0xb2 61(50개) 0xb2 61(50개) &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e70c123d-6c8a-4a24-bbc1-937ccac70f5a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-713c521f-d5de-4836-aa9e-d59c1dd88249&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● RLP 디코딩&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-5606120c-5c1d-45fe-afdd-22ce7e0aaa7f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인코딩인 5가지 케이스가 있는것처럼 디코딩도 5가지 케이스가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8356f931-8083-4fe3-b2eb-3ad28cced70a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-7587325b-e258-479c-9b28-96a3f42b2fab&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 첫 번째 규칙: 첫 번째 바이트가 0x00 ~ 0x7f&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-3d3de08b-8ecf-4aad-b81c-cdab72ae15e5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;값 자체가 문자 데이터&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-699439e4-5a53-4b3e-886f-31adda87d2fc&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 두 번째 규칙: 첫 번째 바이트가 0x80 ~ 0xb7&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-3bdde4cc-77b8-490e-86e0-6e99d9d5b24a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 범위로 시작하면 문자열을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e31dc8b6-bcb6-44cc-99e6-eb48fbe03e6d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9d65b728-884f-4da6-9351-5ea6cce018ef&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 바이트에서 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0x80&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 뺀 값이 문자열의 길이입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-349965bf-10d8-4764-8945-aa54c11f15e1&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 세 번째 규칙: 첫 번째 바이트가 0xb8 ~ 0xbf&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-532efe9e-e39d-4aa2-8f5b-661ce39d6621&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당범위로 시작하면 55바이트를 초과한 문자열을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b55a39a0-e9dd-4053-9625-ea9f55d85cf7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-82c2d4cc-d78c-4808-ba3d-7097a8080e8d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 바이트에서 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xb7&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 뺀 값이 바이트로 표현된 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;RLP 아이템 갯수&lt;/b&gt;&lt;/span&gt;&lt;span&gt;입니다. &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;RLP 아이템 갯수&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만큼 인코딩된 문자가 이어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-325cb82b-1aa6-44bf-8854-12a2df36980d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-5e6963aa-78d0-4588-a1e5-090a30acf139&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 네 번째 규칙: 첫 번째 바이트가 0xc0 ~ 0xf7&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e1eba116-6aad-409e-b2ea-b78c9e0d37e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 범위로 시작하면 배열을 의미합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-034a6492-0d51-4737-be07-f520f85b70f7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0d277631-b7f3-40a7-b049-ebfeaae01475&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 바이트에서 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xc0&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 뺀 값이 배열의 요소 갯수를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d5eafbd4-a288-4914-a5e1-e3a2715aa4d8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-0f4f9534-c264-46a5-889f-b110e7313234&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 다섯 번째 규칙: 첫 번째 바이트가 0xf8 ~ 0xff&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-99e8e923-5e4c-4605-9c2c-552a012d55e9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 범위로 시작하면 배열의 요소 합이 55바이트를 초과한 배열을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-82506e03-5dfb-4841-99c6-8610520d53f1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-06fd234c-d434-4f3b-b363-404d3860f834&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 바이트에서 0xf7을 뺀 값이 배열의 길이를 표현한 바이트의 갯수를 의미합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-53946772-a0fe-480d-bad0-6d693cfbbb3b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0b401ce0-5ae8-44bf-93c8-eda0393f480c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;0xf8&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;0x66&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;0xb2 61(50개) 0xb2 61(50개) 에서&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1ed2ead4-0587-4f4e-9143-10de670e138d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;0xf8 - 0xf7 = 0x01&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f8e92977-1a35-4e94-b58b-dfce04f3fad9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a6abb637-ea02-4415-819a-c6cb7c365b82&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;뒤에 나오는 0x01(1) 만큼 배열의 길이를 의미하는 바이트가 있음&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5076f2ed-dfbc-4902-9bea-d557930ec859&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0524b7fe-e09b-404f-8894-f32ba54ecda1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;0x66(102) 만큼 배열 요소를 의미&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7c832d43-db40-46ab-8948-78a2dbba9c1c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-346d8062-33f1-4394-b730-07173fb936ba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;0xb2 0x61(50개) 0xb2 0x61(50개) =&amp;gt; 해당 값은 두 번째 규칙으로 디코딩할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c43a9c46-e23a-44e0-9137-01c5d5d19cba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-c8603fdf-01cd-4498-a4a3-e5d645f5a202&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● RLP 인코딩의 한계&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-989b022b-829b-4c00-b8b9-9b9d1521c5ac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RLP 인코딩은 &lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;문자열&lt;/b&gt;&lt;/span&gt;&lt;span&gt;과 &lt;/span&gt;&lt;span style=&quot;color: #00a84b;&quot;&gt;&lt;b&gt;배열&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 타입만 구분합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d45aa1b1-c184-4d56-896e-3872b96c3bfa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9cb09ff5-7c52-4f45-9261-bb7f875624e6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;한 가지 예시를 들어보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0e2b7520-46c9-4a7f-b8ad-0b813547c3f8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cac84684-84e7-4f7d-8aeb-bb030636f31a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;숫자 24,930을 RLP 인코딩을 수행하기 위해 해당수를 16진수로 바꿔야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-449b79bb-508f-4ada-a8e2-be775f962cc3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;16진수로 바꾸고 바이트로 끊으면 2진수(1100001 01100010) -&amp;gt; 16진수(0x61 0x62)가 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-21534ffd-fa9c-42d1-a4c8-a89ed1fa0759&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-bbcd7a37-08d6-43e6-8dc6-eaa25ae31508&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;☞ &lt;/b&gt;&lt;u&gt;&lt;b&gt;RLP(24,930) = 0x826162&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-187dab51-9000-4c3f-81c2-3596c069f050&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ffee7654-16ae-408f-9a73-4b7763c19eb4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 결과는 RLP(&quot;ab&quot;)와 동일합니다. 이더리움에서는 이러한 문제를 해결하기 위해 24,930이 아니라 &quot;24930&quot;으로 처리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>ASCII</category>
      <category>Ethereum</category>
      <category>length</category>
      <category>prefix</category>
      <category>recursive</category>
      <category>RLP</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/90</guid>
      <comments>https://meongae.tistory.com/90#entry90comment</comments>
      <pubDate>Sun, 28 Aug 2022 08:22:06 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] web3와 ethers를 이용하여 메타마스크로 트랜잭션 발생하기</title>
      <link>https://meongae.tistory.com/89</link>
      <description>&lt;div id=&quot;SE-ef658acc-b7e3-4cb1-9ddd-421eb456c10b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e83ba0fe-554b-494b-ae40-37ac6b565a5a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;web3와 ethers으로 메타마스크를 이용하여 트랜잭션을 발생하는 방법을 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d5e1e453-8003-4401-964e-13d77a01c400&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-577e1adf-7ab9-4ba3-8a3d-9ec29fcaca9f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;확장프로그램 메타마스크가 설치되어 있다면 메타마스크 프로바이더가 window 객체에 ethereum으로 포함되어 있습니다. 근데 vanilaJS로는 window.ethereum 포함된것을 가지고 오기가 좀 까다로우므로 react에서 발생시켜보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eb8d652c-61a6-4de4-abfd-1c6236a37298&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d67ea1b9-84c6-44b9-be1b-88a71bb7847a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff9300;&quot;&gt;&lt;b&gt;window.web3.currentProvider(레거시)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 또는&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #00b976;&quot;&gt;&lt;b&gt;window.ethereum(현재버전)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;으로 가져오면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-263a3ec7-5caf-462a-8406-e3cd8a1cc9e9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-66f5c08f-9132-4d8b-809d-caf36945f8f3&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● ethers&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-6f8ed684-1ea7-4b38-a343-f10a5f14e53f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;provider에 메타마스크 프로바이더를 넣어줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ea27ffea-93e2-45a9-9a2d-a087077f5b20&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e330346b-5f77-473f-8a4d-153af732c25f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;window?.web3?.currentProvider&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f79fc84a-e239-46e7-9a17-bb09e694d756&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;window.ethereum&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d4f67e4e-53cf-41f6-8361-4b21cbc4ac05&quot;&gt;
&lt;pre id=&quot;code_1661642153515&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { providers, Wallet, utils, Contract } from &quot;ethers&quot;;

function App() {
  
  const clickHandler = async () =&amp;gt; {
    const provider = new providers.Web3Provider(
      window.ethereum || 'http://localhost:8545'
    );
    const signer = provider.getSigner(); // 메타마스크에 선택된 지갑으로 트랜잭션 서명을 함
    console.log(signer)
    
    const txHash = await signer.sendTransaction({
      from: signer.address,
      to: '0xAd46355359aE32263EaFE152a408D9D620844eda',
      value: utils.parseUnits('0.1', 'ether').toHexString()
    })

    console.log(txHash)
  }
  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;button onClick={clickHandler}&amp;gt;
        클릭
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a16f394f-ab5f-4be5-ac19-842b21fbebb1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-4fde45dd-2f8d-4ca8-aeb6-4b7a4aacc846&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 메타마스크 로그인이 정상적으로 되었을 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-4657e7a2-9c06-48d0-873c-36208f954df6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;버튼을 누르면 메타마스크로 트랜잭션 발생을 시키기 위해 팝업을 띄웁니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2af5f1ef-e9ab-481d-95a5-06d5b7bf468d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;910&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXe6mL/btrKJ5voTiF/pVW1MJ47M7dGJmTaIsfmY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXe6mL/btrKJ5voTiF/pVW1MJ47M7dGJmTaIsfmY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXe6mL/btrKJ5voTiF/pVW1MJ47M7dGJmTaIsfmY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXe6mL%2FbtrKJ5voTiF%2FpVW1MJ47M7dGJmTaIsfmY0%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;773&quot; height=&quot;910&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;910&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-91fb9552-cba1-410c-9195-c35016f73746&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-9deb0b28-0357-48c8-a654-a84709097d30&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 메타마스크 로그인이 되어있지 않을 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c83911ea-3a77-4b9c-927c-e0fc55beecc5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;601&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9nz6A/btrKMFQs2W7/jaAkxWdJikOZpMykU2ltbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9nz6A/btrKMFQs2W7/jaAkxWdJikOZpMykU2ltbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9nz6A/btrKMFQs2W7/jaAkxWdJikOZpMykU2ltbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9nz6A%2FbtrKMFQs2W7%2FjaAkxWdJikOZpMykU2ltbk%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;356&quot; height=&quot;601&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;601&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a4f04eae-b7bb-4d68-9bf0-bcfc020cb15c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-83970d1d-4314-44a1-9970-f32b13a22305&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;메타마스크에서 정상적으로 로그인이 되어있지 않았다면 다음과 같이 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-60fdb564-3fa5-46c2-ac10-981fb3900192&quot;&gt;
&lt;pre id=&quot;code_1661642171995&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;index.ts:261 Uncaught (in promise) Error: unknown account #0 (operation=&quot;getAddress&quot;, code=UNSUPPORTED_OPERATION, version=providers/5.6.8)
    at Logger.makeError (index.ts:261:1)
    at Logger.throwError (index.ts:273:1)
    at json-rpc-provider.ts:204:1
    at async Promise.all (:3000/index 1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dc4a653f-dde4-403e-b92c-5431d221ff66&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;62&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sLg44/btrKIxyVUvA/lwRtRKwYdzlKgCMDBwNYLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sLg44/btrKIxyVUvA/lwRtRKwYdzlKgCMDBwNYLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sLg44/btrKIxyVUvA/lwRtRKwYdzlKgCMDBwNYLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsLg44%2FbtrKIxyVUvA%2FlwRtRKwYdzlKgCMDBwNYLk%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;773&quot; height=&quot;62&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;62&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3ee45f0e-8887-4aee-b4a8-0215a960de90&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-2d4d564c-6925-4437-93e1-2e0833508a08&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 승인창에서 확인이 아니라 거부를 눌렀을 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-8c1448fe-6020-414d-ab84-6a723db196dd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;code가 4001인 오브젝트를 exception으로 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d4159239-cfbf-43fa-aaf6-b4fddb47ea48&quot;&gt;
&lt;pre id=&quot;code_1661642183694&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;code&quot;: 4001,
    &quot;message&quot;: &quot;MetaMask Tx Signature: User denied transaction signature.&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0d252c00-9e00-4cc6-89cc-4f56c40d93e9&quot;&gt;
&lt;pre id=&quot;code_1661642207899&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;code&quot;: 4001,
    &quot;message&quot;: &quot;MetaMask Tx Signature: User denied transaction signature.&quot;,
    &quot;stack&quot;: &quot;{\n  \&quot;code\&quot;: 4001,\n  \&quot;message\&quot;: \&quot;MetaMask Tx Signature: User denied transaction signature.\&quot;,\n  \&quot;stack\&quot;: \&quot;Error: MetaMask Tx Signature: User denied transaction signature.\\n    at new i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:308657)\\n    at new o.EthereumProviderError (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:309172)\\n    at c (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:311507)\\n    at Object.userRejectedRequest (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:312738)\\n    at y.&amp;lt;anonymous&amp;gt; (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:30538)\\n    at Object.l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-3.js:10:9069)\\n    at u (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:3:1144)\\n    at a.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:3:1680)\\n    at y._setTransactionStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:76051)\\n    at y.setTxStatusRejected (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:74238)\\n    at z.cancelTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:46625)\\n    at s.&amp;lt;anonymous&amp;gt; (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:22:11434)\\n    at l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:210820)\\n    at s.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:213815)\\n    at w (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41385)\\n    at v (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41200)\\n    at b.push (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:42014)\\n    at t.exports._write (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-6.js:8:435312)\\n    at b (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:54430)\\n    at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:57614\\n    at y.write (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:57641)\\n    at e.exports.m (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:46585)\\n    at l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:210820)\\n    at s.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:213815)\\n    at w (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41385)\\n    at v (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41200)\\n    at b.push (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:42014)\\n    at e.exports._onMessage (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-3.js:10:14413)\\n    at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-3.js:10:14260\&quot;\n}\n  at new i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:308657)\n  at new o.EthereumProviderError (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:309172)\n  at c (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:311507)\n  at Object.userRejectedRequest (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:312738)\n  at y.&amp;lt;anonymous&amp;gt; (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:30538)\n  at Object.l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-3.js:10:9069)\n  at u (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:3:1144)\n  at a.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:3:1680)\n  at y._setTransactionStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:76051)\n  at y.setTxStatusRejected (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:74238)\n  at z.cancelTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:46625)\n  at s.&amp;lt;anonymous&amp;gt; (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:22:11434)\n  at l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:210820)\n  at s.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:213815)\n  at w (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41385)\n  at v (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41200)\n  at b.push (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:42014)\n  at t.exports._write (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-6.js:8:435312)\n  at b (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:54430)\n  at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:57614\n  at y.write (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:57641)\n  at e.exports.m (chrome-extension://nkbihfbeogaeaoehlefnkodbef&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1434e0cc-966b-4573-a143-b69928854176&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbhRaR/btrKGpa1HON/tpPP7p36GFVETwlWkXCDv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbhRaR/btrKGpa1HON/tpPP7p36GFVETwlWkXCDv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbhRaR/btrKGpa1HON/tpPP7p36GFVETwlWkXCDv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbhRaR%2FbtrKGpa1HON%2FtpPP7p36GFVETwlWkXCDv0%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;773&quot; height=&quot;136&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2c3c57e6-91f1-4040-aded-24098309b80c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;SE-f7ac61e9-dd1c-4b0c-8fa6-b4494d9e1a11&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● web3js&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-e45085e6-4d4f-4e06-be1a-1597ac32fa65&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;리엑트 최신 버전에서는 web3가 정상적으로 임포트되지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5346577c-bc75-4e57-a93c-a26c28eb34e2&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/88&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.28 - [블록체인] - [dapp] react에서 web3js 정상적으로 사용하기&lt;/a&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661642229949&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[dapp] react에서 web3js 정상적으로 사용하기&quot; data-og-description=&quot;최신 리액트 버전에서 web3를 사용할 때 다음과 같이 에러가 발생합니다. // src/App.js import Web3 from 'web3'; // 에러발생 지점 function App() { const onClickHandler = async () =&amp;gt; { const web3 = new We..&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/88&quot; data-og-url=&quot;https://meongae.tistory.com/88&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Nsggd/hyPBKk2U6T/6v8aT5eRaSEPdDr1p0X8Xk/img.png?width=773&amp;amp;height=632&amp;amp;face=0_0_773_632,https://scrap.kakaocdn.net/dn/dgA78x/hyPAm0prA1/9LBOX6siMbnjPIHBBq2k1K/img.png?width=773&amp;amp;height=632&amp;amp;face=0_0_773_632,https://scrap.kakaocdn.net/dn/bp5sfl/hyPAyNiutb/3KEJw8foGGG1uZNJcIP7l1/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/88&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/88&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Nsggd/hyPBKk2U6T/6v8aT5eRaSEPdDr1p0X8Xk/img.png?width=773&amp;amp;height=632&amp;amp;face=0_0_773_632,https://scrap.kakaocdn.net/dn/dgA78x/hyPAm0prA1/9LBOX6siMbnjPIHBBq2k1K/img.png?width=773&amp;amp;height=632&amp;amp;face=0_0_773_632,https://scrap.kakaocdn.net/dn/bp5sfl/hyPAyNiutb/3KEJw8foGGG1uZNJcIP7l1/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[dapp] react에서 web3js 정상적으로 사용하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;최신 리액트 버전에서 web3를 사용할 때 다음과 같이 에러가 발생합니다. // src/App.js import Web3 from 'web3'; // 에러발생 지점 function App() { const onClickHandler = async () =&amp;gt; { const web3 = new We..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;provider에 메타마스크 프로바이더를 넣어줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3c80d15a-0250-4ab6-b890-133974507f99&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-73600f9e-90ee-4aaf-8a67-d34d95b59b22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;window?.web3?.currentProvider&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4b5a3dee-21d5-4bbd-98f8-8e1f315996fe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;window.ethereum&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;SE-da151161-d26e-4a01-ab76-57d5412b5b29&quot;&gt;
&lt;pre id=&quot;code_1661642238437&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Web3 from 'web3';

function App() {

  const clickHandler = async () =&amp;gt; {

    const web3 = new Web3(
      window.ethereum || 'http://localhost:8545'
    );
    const accounts = await web3.eth.requestAccounts(); // 메타마스크에 선택된 지갑으로 트랜잭션 서명을 함 
    console.log(accounts);

    const tx = await web3.eth.sendTransaction({
      from: accounts[0],
      to: '0xAd46355359aE32263EaFE152a408D9D620844eda',
      value: web3.utils.toWei('0.1', 'ether'),
      data: ''
    })
    console.log(tx)
  }

  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;button onClick={clickHandler}&amp;gt;클릭&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-523911c9-0b76-4fb1-8295-6529e7dc7d8d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-3c002b23-4ba5-4672-8fd2-6f286612ab01&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 메타마스크 로그인이 정상적으로 되었을 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-624e987b-68e7-48b2-935c-e1762e001782&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;910&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kR7LD/btrKK9RPBSX/4TDJszpNRgY9qz0XKX8lR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kR7LD/btrKK9RPBSX/4TDJszpNRgY9qz0XKX8lR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kR7LD/btrKK9RPBSX/4TDJszpNRgY9qz0XKX8lR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkR7LD%2FbtrKK9RPBSX%2F4TDJszpNRgY9qz0XKX8lR0%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;773&quot; height=&quot;910&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;910&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3678c112-c051-4149-8367-f09ae3238af9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ec405672-0769-4c1e-a301-fd028f987194&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-474e86e1-22af-4029-ac9a-6c0bf8f30b1d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 메타마스크 로그인이 되어있지 않을 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-669d0ca5-9935-499e-9127-7775311c37d3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;601&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z4u66/btrKHwAwbT0/x6i7zrq2HdWHZMquuCI8ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z4u66/btrKHwAwbT0/x6i7zrq2HdWHZMquuCI8ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z4u66/btrKHwAwbT0/x6i7zrq2HdWHZMquuCI8ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz4u66%2FbtrKHwAwbT0%2Fx6i7zrq2HdWHZMquuCI8ck%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;356&quot; height=&quot;601&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;601&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-07bcdaad-d9f6-4104-a468-352373183819&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3db4dde2-8351-4612-830f-bfddde0b93e7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;web3의 경우는 메타마스크 로그인창을 띄웁니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f29f13ba-ccbf-4118-a99f-973472c38715&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;905&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ekDaR2/btrKGw2iTrO/CP5OMUfJVHnykJ1Kjoc5J1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ekDaR2/btrKGw2iTrO/CP5OMUfJVHnykJ1Kjoc5J1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ekDaR2/btrKGw2iTrO/CP5OMUfJVHnykJ1Kjoc5J1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FekDaR2%2FbtrKGw2iTrO%2FCP5OMUfJVHnykJ1Kjoc5J1%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;773&quot; height=&quot;905&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;905&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8640ae24-5bf8-4dc2-a373-6dc107654e85&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-490a2754-a1ff-4a4e-a82c-161115392d0f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 로그인을 하게되면 다음과 같이 트랜잭션 확인창을 띄워줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-28cfea42-4dab-4375-8c88-1921d7475035&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;905&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNFWXu/btrKHv2EUUI/R6KKOSOFUZaNXKT6JrDQu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNFWXu/btrKHv2EUUI/R6KKOSOFUZaNXKT6JrDQu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNFWXu/btrKHv2EUUI/R6KKOSOFUZaNXKT6JrDQu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNFWXu%2FbtrKHv2EUUI%2FR6KKOSOFUZaNXKT6JrDQu0%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;773&quot; height=&quot;905&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;905&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-42175948-1681-4431-a45a-a694167e73e9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-8bbc8c8f-8249-4126-bf44-fd91e69f92c7&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 승인창에서 확인이 아니라 거부를 눌렀을 때&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-cd119144-7995-466d-b22c-91e71ddd326d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;code가 4001인 오브젝트를 exception으로 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-778183ea-27f3-4e1e-8bb0-7609a8901b58&quot;&gt;
&lt;pre id=&quot;code_1661642274204&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;code&quot;: 4001,
    &quot;message&quot;: &quot;MetaMask Tx Signature: User denied transaction signature.&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-461086cd-772e-4f7a-b3c9-1d07e8294306&quot;&gt;
&lt;pre id=&quot;code_1661642286036&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;code&quot;: 4001,
    &quot;message&quot;: &quot;MetaMask Tx Signature: User denied transaction signature.&quot;,
    &quot;stack&quot;: &quot;{\n  \&quot;code\&quot;: 4001,\n  \&quot;message\&quot;: \&quot;MetaMask Tx Signature: User denied transaction signature.\&quot;,\n  \&quot;stack\&quot;: \&quot;Error: MetaMask Tx Signature: User denied transaction signature.\\n    at new i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:308657)\\n    at new o.EthereumProviderError (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:309172)\\n    at c (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:311507)\\n    at Object.userRejectedRequest (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:312738)\\n    at y.&amp;lt;anonymous&amp;gt; (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:30538)\\n    at Object.l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-3.js:10:9069)\\n    at u (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:3:1144)\\n    at a.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:3:1680)\\n    at y._setTransactionStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:76051)\\n    at y.setTxStatusRejected (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:74238)\\n    at z.cancelTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:46625)\\n    at s.&amp;lt;anonymous&amp;gt; (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:22:11434)\\n    at l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:210820)\\n    at s.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:213815)\\n    at w (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41385)\\n    at v (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41200)\\n    at b.push (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:42014)\\n    at t.exports._write (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-6.js:8:435312)\\n    at b (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:54430)\\n    at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:57614\\n    at y.write (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:57641)\\n    at e.exports.m (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:46585)\\n    at l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:210820)\\n    at s.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:213815)\\n    at w (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41385)\\n    at v (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41200)\\n    at b.push (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:42014)\\n    at e.exports._onMessage (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-3.js:10:14413)\\n    at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-3.js:10:14260\&quot;\n}\n  at new i (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:308657)\n  at new o.EthereumProviderError (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:309172)\n  at c (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:311507)\n  at Object.userRejectedRequest (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-2.js:1:312738)\n  at y.&amp;lt;anonymous&amp;gt; (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:30538)\n  at Object.l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-3.js:10:9069)\n  at u (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:3:1144)\n  at a.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:3:1680)\n  at y._setTransactionStatus (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:76051)\n  at y.setTxStatusRejected (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:74238)\n  at z.cancelTransaction (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:1:46625)\n  at s.&amp;lt;anonymous&amp;gt; (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/background-4.js:22:11434)\n  at l (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:210820)\n  at s.emit (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-1.js:20:213815)\n  at w (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41385)\n  at v (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:41200)\n  at b.push (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:42014)\n  at t.exports._write (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-6.js:8:435312)\n  at b (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:54430)\n  at chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:57614\n  at y.write (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/common-7.js:1:57641)\n  at e.exports.m (chrome-extension://nkbihfbeogaeaoehlefnkodbef&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dd1d6787-9d41-4844-83f1-c560531eff7a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xGumf/btrKK86tRCX/GYiC6JDkDWXeAplyuGND50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xGumf/btrKK86tRCX/GYiC6JDkDWXeAplyuGND50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xGumf/btrKK86tRCX/GYiC6JDkDWXeAplyuGND50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxGumf%2FbtrKK86tRCX%2FGYiC6JDkDWXeAplyuGND50%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;773&quot; height=&quot;137&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-069ff5a4-7582-47e6-b69d-b21e39de53a6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e3150dc5-3992-444f-9eb2-140e1e533cfd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>Ethereum</category>
      <category>ethers</category>
      <category>JavaScript</category>
      <category>web3</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/89</guid>
      <comments>https://meongae.tistory.com/89#entry89comment</comments>
      <pubDate>Sun, 28 Aug 2022 08:18:19 +0900</pubDate>
    </item>
    <item>
      <title>[dapp] react에서 web3js 정상적으로 사용하기</title>
      <link>https://meongae.tistory.com/88</link>
      <description>&lt;div id=&quot;SE-744e7769-b81d-4b7b-8996-c6c52f66940a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d6742a98-e799-4f4e-adbc-3eb5568b874c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최신 리액트 버전에서 web3를 사용할 때 다음과 같이 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cee26f2c-d4e6-46ac-a202-0b89b510cc9a&quot;&gt;
&lt;pre id=&quot;code_1661642055827&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// src/App.js

import Web3 from 'web3'; // 에러발생 지점

function App() {

  const onClickHandler = async () =&amp;gt; {

    const web3 = new Web3(
      window?.web3?.currentProvider //  메타마스크 프로바이더
      || 'http://localhost:8545'
    );
    const accounts = await web3.eth.requestAccounts();
    console.log(accounts)
    const tx = await web3.eth.sendTransaction({
      from: accounts[0],
      to: '0xAd46355359aE32263EaFE152a408D9D620844eda',
      value: web3.utils.toWei('1', 'ether'),
      data: ''
    })
    console.log(tx)
  }

  return (
    &amp;lt;div className=&quot;App&quot;&amp;gt;
      &amp;lt;button onClick={onClickHandler}&amp;gt;Send&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f624686e-5005-4231-a531-93d0e8acf003&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8434ab20-48ed-4426-ae2c-519dab804da5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;web3를 import하는 지점에서 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7f5832f5-fcd3-4f3b-964d-a9f0e02e6df9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;632&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/53IC4/btrKHbDmeYO/f8sYvTWKFsQE6QSF97kEy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/53IC4/btrKHbDmeYO/f8sYvTWKFsQE6QSF97kEy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/53IC4/btrKHbDmeYO/f8sYvTWKFsQE6QSF97kEy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F53IC4%2FbtrKHbDmeYO%2Ff8sYvTWKFsQE6QSF97kEy0%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;773&quot; height=&quot;632&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;632&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1c44c9a6-3049-4708-a06a-957407362f49&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ed9f36fb-24f7-4dca-ac43-b8e878c235e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최신 CRA에서 정상적으로 폴리필이 동작하지 않아 생기는 문제입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-de0e2185-aff5-462e-bac0-2d210fb45870&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ec349974-1396-4bcf-95e0-efe032e7cae7&quot;&gt;
&lt;pre id=&quot;code_1661642064355&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx create-react-app [프로젝트 이름]

$ npm install web3 web3-utils&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-38d3fe79-7277-4c0b-bebc-6be6c7536420&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-85105f86-1067-4e20-b04d-71db706b0efa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추가 의존성 설치&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7609a981-60fc-4386-a115-db30b9e9a11d&quot;&gt;
&lt;pre id=&quot;code_1661642071529&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save-dev react-app-rewired crypto-browserify stream-browserify assert stream-http https-browserify os-browserify url buffer process&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aebc10a9-7d11-4f58-85cc-cc4979ed8746&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6d5e0623-2554-4017-a338-573dc08f38f5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹팩 오버라이딩 하기&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6d13820d-9fee-4a00-b2aa-282dd3e7165a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #00b976;&quot;&gt;&lt;b&gt;config-overrides.js&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d78ccae1-4b64-4316-88fa-dad87b236cc0&quot;&gt;
&lt;pre id=&quot;code_1661642081188&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const webpack = require('webpack');

module.exports = function override(config) {
    const fallback = config.resolve.fallback || {};
    Object.assign(fallback, {
        &quot;crypto&quot;: require.resolve(&quot;crypto-browserify&quot;),
        &quot;stream&quot;: require.resolve(&quot;stream-browserify&quot;),
        &quot;assert&quot;: require.resolve(&quot;assert&quot;),
        &quot;http&quot;: require.resolve(&quot;stream-http&quot;),
        &quot;https&quot;: require.resolve(&quot;https-browserify&quot;),
        &quot;os&quot;: require.resolve(&quot;os-browserify&quot;),
        &quot;url&quot;: require.resolve(&quot;url&quot;)
    })
    config.resolve.fallback = fallback;
    config.plugins = (config.plugins || []).concat([
        new webpack.ProvidePlugin({
            process: 'process/browser',
            Buffer: ['buffer', 'Buffer']
        })
    ])
    return config;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e8fcd02a-c419-4c53-be65-d37a0185e9d2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c1dc12fb-2962-4c2f-8da5-77b52b28b9e2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #00b976;&quot;&gt;&lt;u&gt;&lt;i&gt;&lt;b&gt;package.json&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;&lt;span&gt; script 수정&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ae41ec7a-18a9-4a74-968b-5bb61c44fc86&quot;&gt;
&lt;pre id=&quot;code_1661642087810&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;react-app-rewired start&quot;,
    &quot;build&quot;: &quot;react-app-rewired build&quot;,
    &quot;test&quot;: &quot;react-app-rewired test&quot;,
    &quot;eject&quot;: &quot;react-scripts eject&quot;
  },&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2d0e67bc-22dd-4b54-b62f-a6fe5b451d5e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5a5a2d72-f887-4ba6-bca1-be33952651cc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다시 실행하면 정상적으로 동작하는 모습을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>JavaScript</category>
      <category>REACT</category>
      <category>web3</category>
      <category>web3.js</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/88</guid>
      <comments>https://meongae.tistory.com/88#entry88comment</comments>
      <pubDate>Sun, 28 Aug 2022 08:14:59 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] web3.js와 같은 ethers 알아보기</title>
      <link>https://meongae.tistory.com/87</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ethers는 web3.js처럼 이더리움 네트워크를 조회하고 조작할 수 있는 인터페이스를 제공하는 라이브러리입니다. 그렇다면 web3.js대신 ethers.js를 사용해야하는 이유는 무엇일까?&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-53b2841d-dfe7-48ec-8104-600a03a1a5cf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c0ece363-f900-4b73-b838-e9bbbff02dea&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ethers는 provider와 signer를 주입하는 형태로 유연한 코드 작성이 가능하다고 생각합니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;SE-5e7eaf5a-d419-4186-bde0-965297f40ed5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-71da71c9-b647-4c30-bd47-8928ca5afd4e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 설치&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b1be2fac-25fd-40cc-afec-b2510893dfc1&quot;&gt;
&lt;pre id=&quot;code_1661641503070&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save ethers&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06e2a492-eb5a-48d4-855a-4736b639c5c1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1c9d2fd7-2035-46c0-a272-fa2b761619c6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ethers는 크게 4개의 객체를 제공합니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-f765e952-eb9f-4b26-b0c8-3282f296d34c&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ CommonJS&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f6492636-56d8-4eb8-aa51-7dfa4437f93e&quot;&gt;
&lt;pre id=&quot;code_1661641518815&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { providers, Wallet, utils, Contract } = require('ethers');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4fa58783-d366-423c-85d1-7c463a400c51&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-803e8539-6d21-4545-90e8-6695f4852217&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;▶ ESM&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6eabfbe9-0937-4055-be7c-a018a98d68ba&quot;&gt;
&lt;pre id=&quot;code_1661641523933&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { providers, Wallet, utils, Contract } from &quot;ethers&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a5d03789-c199-4789-89e5-5e0a1bee7dd2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-feb79083-495b-4bfb-b5a6-d49d7bd6b3a5&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ CDN&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06a0c7d5-63a2-4c54-8f74-d5a6bccaddea&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-56d3550a-9f57-4a3a-9e7a-eca07b8c8eb1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641545998&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;
    import { providers, Wallet, utils, Contract } from &quot;https://cdn.ethers.io/lib/ethers-5.2.esm.min.js&quot;;
&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/ethers/5.6.9/ethers.umd.min.js&quot; integrity=&quot;sha512-Veaz5IU2iRpa0BBrJlJeRgfJ7OAHWtVJZTXvgdH7s3ffsLUChllMCqC0Bb+eeRxGlrZ06iYIE/R3KsciCrgv3A==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot;&amp;gt;
&amp;lt;/script&amp;gt;

&amp;lt;script&amp;gt;
  const { providers, Wallet, utils, Contract } = ethers.ethers;
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-64bf9ac7-a0d2-49d8-acf4-f4723fe22ddc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-d34678ce-7ce1-4140-a3d5-5087f3da129d&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● providers&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-e60c5235-04b4-4f2a-84d8-394c376b843e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;providers는 이더리움 노드와 연결합니다. 블록, 트랜잭션 조회등을 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-798e1f78-397c-4e6a-b216-25e174a6e846&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 노드연결&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-11372ea6-093e-4bb5-9b8b-cb4ee6267f97&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0b052fb9-a8f2-4dca-a187-a62bad2404ce&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641563415&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const provider = new providers.JsonRpcProvider(url);

const provider = new providers.JsonRpcProvider('http://localhost:8545');&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-d0617ebb-8429-4762-8076-89f5c7e75559&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약, metamask의 provider를 이용하고 싶다면 다음과 같이 이용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f63e6d9b-e835-4c29-a853-f380f0e7a94e&quot;&gt;
&lt;pre id=&quot;code_1661641576542&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const provider = new ethers.providers.Web3Provider(window.ethereum)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-67ba1f36-302a-43bc-9a73-361be769b7f0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-c4c01338-73c0-4e2d-af9a-fd8af036d80f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 최근 블록번호 조회&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6ad29951-5de4-413d-b2bd-f67201211e7e&quot;&gt;
&lt;pre id=&quot;code_1661641588616&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const block = await provider.getBlockNumber()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f85f74ae-9a89-4c41-bd1f-69fd2c2431e0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-2e27f7ef-4fce-4659-a0bf-b5cd86ef201b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 블록조회&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2bee59b9-21fd-4c22-a2ec-c24478e63d09&quot;&gt;
&lt;pre id=&quot;code_1661641605949&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const block0 = await provider.getBlock(0)

{
  hash: '0xe4b7283f03a18236615e883d91595dc6cf12119ed14d0179c7e29f5f80f2c94d',
  parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
  number: 0,
  timestamp: 1650158272,
  nonce: '0x0000000000000000',
  difficulty: 0,
  gasLimit: BigNumber { _hex: '0x6691b7', _isBigNumber: true },
  gasUsed: BigNumber { _hex: '0x00', _isBigNumber: true },
  miner: '0x0000000000000000000000000000000000000000',
  extraData: '0x',
  transactions: [], 
  _difficulty: BigNumber { _hex: '0x00', _isBigNumber: true }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-728b4de7-b216-47c8-a46b-dbd3ac1900f5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-811106ef-013b-4cf4-a981-20b7b21897a2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641615190&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const txs = await provider.getBlockWithTransactions(0)
{
  hash: '0xe4b7283f03a18236615e883d91595dc6cf12119ed14d0179c7e29f5f80f2c94d',
  parentHash: '0x0000000000000000000000000000000000000000000000000000000000000000',
  number: 0,
  timestamp: 1650158272,
  nonce: '0x0000000000000000',
  difficulty: 0,
  gasLimit: BigNumber { _hex: '0x6691b7', _isBigNumber: true },
  gasUsed: BigNumber { _hex: '0x00', _isBigNumber: true },
  miner: '0x0000000000000000000000000000000000000000',
  extraData: '0x',
  transactions: [],
  _difficulty: BigNumber { _hex: '0x00', _isBigNumber: true }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-a6d87e82-bcd2-47ad-8e9c-fbb5b5c3ddd4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;getBlock&lt;/b&gt;&lt;/span&gt;&lt;span&gt;과 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;getBlockWithTransactions&lt;/b&gt;&lt;/span&gt;&lt;span&gt;의 차이는 transactions에 있습니다. &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;getBlock&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은&lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt; 트랜잭션 해시 목록&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 가지고 있으며 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;getBlockWithTransactions&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;트랜잭션 객체목록&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 가지고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4c6d1937-e705-4f5a-8661-76eeb03c8e27&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-0d08ebd4-e046-4402-b0bd-2fd0b213bd1b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 조회&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3cce15d5-d66a-4516-864f-bffc7b0bf8cf&quot;&gt;
&lt;pre id=&quot;code_1661641634664&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const tx = await provider.getTransaction(&quot;0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0&quot;);
{
  accessList: null,
  blockHash: '0x8a179bc6cb299f936c4fd614995e62d597ec6108b579c23034fb220967ceaa94',
  blockNumber: 12598244,
  chainId: 1,
  confirmations: 1869134,
  creates: '0x733aF852514e910E2f8af40d61E00530377889E9',
  data: '0x608060405234801561001057600080fd5b5060405161062438038061062483398101604081905261002f916100cd565b60405163c47f002760e01b815260206004820152600d60248201526c0daead8e8d2c6c2d8d85ccae8d609b1b60448201526001600160a01b0382169063c47f002790606401602060405180830381600087803b15801561008e57600080fd5b505af11580156100a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100c691906100fb565b5050610113565b6000602082840312156100de578081fd5b81516001600160a01b03811681146100f4578182fd5b9392505050565b60006020828403121561010c578081fd5b5051919050565b610502806101226000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80634c0770b914610030575b600080fd5b61004361003e366004610309565b61005b565b60405161005293929190610389565b60405180910390f35b600060608085841461006c57600080fd5b8567ffffffffffffffff81111561009357634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156100bc578160200160208202803683370190505b5091508567ffffffffffffffff8111156100e657634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561011957816020015b60608152602001906001900390816101045790505b50905060005b86811015610235576101cd8a8a8a8a8581811061014c57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061016191906102db565b89898681811061018157634e487b7160e01b600052603260045260246000fd5b90506020028101906101939190610460565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061024592505050565b8483815181106101ed57634e487b7160e01b600052603260045260246000fd5b6020026020010184848151811061021457634e487b7160e01b600052603260045260246000fd5b6020908102919091010191909152528061022d816104a5565b91505061011f565b5043925096509650969350505050565b6000606060405190506000815260208101604052600080845160208601878afa9150843d101561028857603f3d01601f191681016040523d81523d6000602083013e5b94509492505050565b60008083601f8401126102a2578182fd5b50813567ffffffffffffffff8111156102b9578182fd5b6020830191508360208260051b85010111156102d457600080fd5b9250929050565b6000602082840312156102ec578081fd5b81356001600160a01b0381168114610302578182fd5b9392505050565b60008060008060008060808789031215610321578182fd5b8635955060208701359450604087013567ffffffffffffffff80821115610346578384fd5b6103528a838b01610291565b9096509450606089013591508082111561036a578384fd5b5061037789828a01610291565b979a9699509497509295939492505050565b60006060820185835260206060818501528186518084526080860191508288019350845b818110156103c9578451835293830193918301916001016103ad565b5050848103604086015285518082528282019350600581901b82018301838801865b8381101561045057601f1980868503018852825180518086528a5b81811015610421578281018a01518782018b01528901610406565b81811115610431578b8a83890101525b5098880198601f019091169390930186019250908501906001016103eb565b50909a9950505050505050505050565b6000808335601e19843603018112610476578283fd5b83018035915067ffffffffffffffff821115610490578283fd5b6020019150368190038213156102d457600080fd5b60006000198214156104c557634e487b7160e01b81526011600452602481fd5b506001019056fea264697066735822122083b5dc25b3c9256aa4244eddaf9e4b5fccd09a45ec4e0174f2c900de7144602d64736f6c63430008040033000000000000000000000000084b1c3c81545d370f3634392de611caabff8148',
  from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
  gasLimit: { BigNumber: &quot;443560&quot; },
  gasPrice: { BigNumber: &quot;10100000000&quot; },
  hash: '0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0',
  nonce: 745,
  r: '0xaf2b969de6dfb234fb8843f47a029636abb1ef52f26bb8bb615bbabcf23808e9',
  s: '0x3dd61cd8df015e0af5689a249dd3224ee71f2b04917b7b4c14f7e68bb3a4ec17',
  to: null,
  transactionIndex: 315,
  type: 0,
  v: 38,
  value: { BigNumber: &quot;0&quot; },
  wait: [Function]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5d2cb892-8679-411d-98f0-ac8f36bfce2b&quot;&gt;
&lt;pre id=&quot;code_1661641642454&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const tx = await provider.getTransactionReceipt(&quot;0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0&quot;);

{
  blockHash: '0x8a179bc6cb299f936c4fd614995e62d597ec6108b579c23034fb220967ceaa94',
  blockNumber: 12598244,
  byzantium: true,
  confirmations: 1869134,
  contractAddress: '0x733aF852514e910E2f8af40d61E00530377889E9',
  cumulativeGasUsed: { BigNumber: &quot;12102324&quot; },
  effectiveGasPrice: { BigNumber: &quot;10100000000&quot; },
  from: '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
  gasUsed: { BigNumber: &quot;443560&quot; },
  logs: [
    {
      address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
      blockHash: '0x8a179bc6cb299f936c4fd614995e62d597ec6108b579c23034fb220967ceaa94',
      blockNumber: 12598244,
      data: '0x000000000000000000000000084b1c3c81545d370f3634392de611caabff8148',
      logIndex: 160,
      topics: [
        '0xce0457fe73731f824cc272376169235128c118b49d344817417c6d108d155e82',
        '0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2',
        '0x4774f6d3b3d08b5ec00115f0e2fddb92604b39e52b0dc908c6f8fcb7aa5d2a9a'
      ],
      transactionHash: '0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0',
      transactionIndex: 315
    },
    {
      address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
      blockHash: '0x8a179bc6cb299f936c4fd614995e62d597ec6108b579c23034fb220967ceaa94',
      blockNumber: 12598244,
      data: '0x000000000000000000000000a2c122be93b0074270ebee7f6b7292c7deb45047',
      logIndex: 161,
      topics: [
        '0x335721b01866dc23fbee8b6b2c7b1e14d6f05c28cd35a2c934239f94095602a0',
        '0x790fdce97f7b2b1c4c5a709fb6a49bf878feffcaa85ed0245f6dff09abcefda7'
      ],
      transactionHash: '0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0',
      transactionIndex: 315
    }
  ],
  logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000004000000000000010000000000000020000000000000000000040000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000040000000000000000100004000000000000008000040000000000000000000000000000000000005000000000041000000000000000000000000000000000000000000000000100000000000000001000000000000000000000',
  status: 1,
  to: null,
  transactionHash: '0x5b73e239c55d790e3c9c3bbb84092652db01bb8dbf49ccc9e4a318470419d9a0',
  transactionIndex: 315,
  type: 0
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c611a5d6-4a38-4aca-959f-1a50764a730f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-0dc5d59e-ec83-4f75-9776-5d2b1ab7cba4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 이더조회&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-60ec7039-c694-464e-8b9a-9e617e797c23&quot;&gt;
&lt;pre id=&quot;code_1661641653478&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const balance = await provider.getBalance('0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17')

BigNumber { _hex: '0x056bc75e2d63100000', _isBigNumber: true }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-001b7f33-c0b2-48a0-b755-e0df9bf676db&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1eb1d2d7-d36b-4858-a950-bd72f057b950&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;단위변경은 utils를 이용하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-7871905d-8893-41f5-b660-5400c9875ab6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 수수료 조회&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-81c83fa3-1b7e-4b5d-b459-6bc7b845570f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션을 만들기 위해 필요한 수수료 조회 메서드입니다. 이는 EIP1559 방식을 기준으로 조회합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d9d67d94-8057-497c-a4d1-f86d58bf4c93&quot;&gt;
&lt;pre id=&quot;code_1661641665169&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fee = await provider.getFeeData();

{
  maxFeePerGas: null,
  maxPriorityFeePerGas: null,
  gasPrice: BigNumber { _hex: '0x04a817c800', _isBigNumber: true }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4145a5a0-0ced-4e72-a448-fb49ab042a72&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-abcfccf3-d57f-49e2-aa1d-0a352fe3632a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;maxFeePerGas와 maxPriorityFeePerGas 모두 gasPrice와 같은 데이터 타입을 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-5f7fe80a-9be7-4201-9280-7de497af81f0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 수수료 추청&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-16e3a9a7-2639-4642-bf1a-950d80012323&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션이 정상적으로 실행되었을 때 사용되는 가스량 추청을 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f72b74df-f521-44d4-93dc-2914433f0e87&quot;&gt;
&lt;pre id=&quot;code_1661641675620&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;await provider.estimateGas({
  to: &quot;0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2&quot;,   // Wrapped ETH address
  data: &quot;0xd0e30db0&quot;,   // `function deposit() payable`
  value: parseEther(&quot;1.0&quot;)   // 1 ether
});

{ BigNumber: &quot;27938&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0bc0ce94-b24d-487e-a582-1548ce7c235c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-126bb154-7235-4f3e-9f16-b173675d7849&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; nonce 조회&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-ecee9533-749b-4eb7-9136-89c0a791a9b9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nonce란 발생된 트랜잭션 수 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-89025d21-972f-4509-8243-521ec82e40a1&quot;&gt;
&lt;pre id=&quot;code_1661641698071&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const address = '0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17';
const nonce = await provider.getTransactionCount(address, &quot;latest&quot;)

0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f649e113-49f5-4df8-9ec8-0258404032c9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-ca2890ab-7eca-4f2d-8fdc-1c842c126dca&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 발생&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0cf65683-36e7-400b-9554-b01702307ab6&quot;&gt;
&lt;pre id=&quot;code_1661641706143&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const signedTx = &quot;0xf8690401825208945555763613a12d8f3e73be831dff8598089d3dca882b992b75cbeb600080820a96a0e3767d1e99c6090a5d00532fe11e2acf3be9228f1f8df7ce9d3c5c6ca3dac151a0594869ee73fbf7394c82e080b1bc734536b67832d2abab5b7bedc79f297bb338&quot;;
await provider.sendTransaction(signedTx);

{
  chainId: 1337,
  confirmations: 0,
  data: '0x',
  from: '0x77C44C0D1D37050e9250415Ee96401B5ac270856',
  gasLimit: { BigNumber: &quot;21000&quot; },
  gasPrice: { BigNumber: &quot;1&quot; },
  hash: '0x1c392c05e5f293ce4e1367101233513ce09575c67d7f3ee519d59c2d22b9dde9',
  nonce: 4,
  r: '0xe3767d1e99c6090a5d00532fe11e2acf3be9228f1f8df7ce9d3c5c6ca3dac151',
  s: '0x594869ee73fbf7394c82e080b1bc734536b67832d2abab5b7bedc79f297bb338',
  to: '0x5555763613a12D8F3e73be831DFf8598089d3dCa',
  type: null,
  v: 2710,
  value: { BigNumber: &quot;3141590000000000000&quot; },
  wait: [Function]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a6355d38-3b76-4e87-8be0-a76afbdd5b36&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c3509bea-ff90-45db-900e-2c97e68ffedd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서명된 트랜잭은 다음과 같이 만들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-57217adf-a032-45cc-b6dc-8310c5560fde&quot;&gt;
&lt;pre id=&quot;code_1661641713063&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const signer = Wallet.createRandom()
const signed = await signer.signTransaction({
  to: '0x6BAE09696c44D0fcF157Cf72b1930632AF435A97',
  from: signer.address,
  value: utils.parseEther('0.1'),
})

await provider.sendTransaction(signedTx);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-79ccea1e-643b-453b-9735-6035c798ddb2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f3458478-4ab8-42b9-b3ac-90744ae24f10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 sendTransaction은 서명된 문자열이 아닌 오브젝트를 받을 수 있습니다. 이때 from은 생성된 지갑주소가 들어갑니다. wallet을 생성하고 니모닉, 키스토어 파일, 개인키를 이용하여 복구하는 방법은 아래에서 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5f457214-7218-4fb4-945b-4124cbc17b88&quot;&gt;
&lt;pre id=&quot;code_1661641720527&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const signer = Wallet.createRandom()

const txHash = await signer.sendTransaction({
  to: '0xAd46355359aE32263EaFE152a408D9D620844eda',
  value: utils.parseUnits('0.1', 'ether').toHexString()
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ce71330c-4d66-4ee4-900d-6a3fbcc207e5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-45d1eb57-561f-4b50-bff7-f79ec8100383&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 이벤트 수신&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0113b389-2dd0-4957-9311-a5113e46ae6a&quot;&gt;
&lt;pre id=&quot;code_1661641731014&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;provider.on('block', (block) =&amp;gt; {
  console.log(block)
})

1
2
3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b23c57f3-c1b4-42c4-9d8e-6f9d9eb4b07b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cc273274-4586-415b-a5bb-4a27b7ec2794&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 네트워크에 블록이 생성되면 생성된 블록번호를 전달받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ca3d260d-1da4-47c4-bca3-56165ee73729&quot;&gt;
&lt;pre id=&quot;code_1661641738572&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;provider.on(&quot;pending&quot;, (tx) =&amp;gt; {
  console.log(tx)
});

{
  hash: '0x5a224e5f2ab73bfbe382dda2260adb8c5e2957606991b8b9b2ab7c33324c8323',
  type: 0,
  accessList: null,
  blockHash: '0xb13106233b4173006fda0e39bd2af24264d49f1b88f2f828b0b4f1fd3fee77b6',
  blockNumber: 9,
  transactionIndex: 0,
  confirmations: 1,
  from: '0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17',
  gasPrice: BigNumber { _hex: '0x04a817c800', _isBigNumber: true },
  gasLimit: BigNumber { _hex: '0x011a59', _isBigNumber: true },
  to: null,
  value: BigNumber { _hex: '0x00', _isBigNumber: true },
  nonce: 8,
  data: '0x60566050600b82828239805160001a6073146043577f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122024e006b709493803f07277c09b5c327910ed1595e233a5d24959eacff659640364736f6c634300080d0033',
  r: '0xa93dc61c988f92aba88db265bdcd03e8412066c2d2b409c97b34ab8da882aa1a',
  s: '0x71babaf613b91c91a6979661dae2f28dfb1d5e7f9e9c2abbac7d84f5e286a516',
  v: 38,
  creates: '0x85E8E89867bc699278Da7276d32E4fd856B3Afc8',
  chainId: 1,
  wait: [Function (anonymous)]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-42ebf640-bc51-4118-8d3a-4179b73525de&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b7275969-3e3c-484d-9493-ccea38ee915f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;팬딩중인 트랜잭션을 수신합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e198e228-458d-460c-8dd3-e7a9677325b5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-f9a3a17d-cefa-4703-b2fb-f621dca2bd7a&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● Wallet&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-84f58d97-2162-44ef-8833-071e60788bde&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Wallet은 개인키/공개키를 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-7b1a6f20-5d13-471c-8b8b-dfd4e3e92564&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 키(주소) 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1cfc10dd-dfbc-445c-926f-a1f3c349f565&quot;&gt;
&lt;pre id=&quot;code_1661641759359&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const signer = Wallet.createRandom()

console.log(signer)
console.log(signer._signingKey())
console.log(signer._mnemonic())

Wallet {
  _isSigner: true,
  _signingKey: [Function (anonymous)],
  address: '0xf3a1F20176cd7F877737012ca8FCd3e32B5bbc81',
  _mnemonic: [Function (anonymous)],
  provider: null
}
SigningKey {
  curve: 'secp256k1',
  privateKey: '0xc9ea026885ea45fd27d06049614bc1e6474fd5208dcd008a25e4f5c8297a11fd',
  publicKey: '0x0462c4b51b0a8623510168d1ac42d8731bbd38b6aa3c037b96782b987e76d695913efa32b8552d42c51fd7dc2c6ff06c8e17d75beeda5e55fa7da955850fe50ef4',
  compressedPublicKey: '0x0262c4b51b0a8623510168d1ac42d8731bbd38b6aa3c037b96782b987e76d69591',
  _isSigningKey: true
}
{
  phrase: 'clown unveil parrot rebuild trial convince box glass gun trumpet garbage electric',
  path: &quot;m/44'/60'/0'/0/0&quot;,
  locale: 'en'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-160fcdbf-dae3-4df7-be23-d7465cdb0727&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d699d5ed-109c-4152-94d1-1d64afcda978&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;create 메서드를 이용하면 키스토어를 생성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fafdd74c-7b69-4f05-aa2f-bdb0c4b67617&quot;&gt;
&lt;pre id=&quot;code_1661641770048&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const password = '123456'
const signer = Wallet.createRandom()
const keystore = await signer.encrypt(password);
console.log(keystore)

{&quot;address&quot;:&quot;84db1f6c4b16cda79f4dc34404445fabe55b97bf&quot;,&quot;id&quot;:&quot;fb49150e-baa5-4325-a3c1-4f8547c118cb&quot;,&quot;version&quot;:3,&quot;Crypto&quot;:{&quot;cipher&quot;:&quot;aes-128-ctr&quot;,&quot;cipherparams&quot;:{&quot;iv&quot;:&quot;39fe92c0b9ccba464e25e63686695f05&quot;},&quot;ciphertext&quot;:&quot;476c18b348830e566c815df1669e281e45777e282494deea857425864b778421&quot;,&quot;kdf&quot;:&quot;scrypt&quot;,&quot;kdfparams&quot;:{&quot;salt&quot;:&quot;a4f06b8ee274dbb763e540cf93d3cded6ceaa43a928381c463767b7e2ee76f33&quot;,&quot;n&quot;:131072,&quot;dklen&quot;:32,&quot;p&quot;:1,&quot;r&quot;:8},&quot;mac&quot;:&quot;3aed307763f9e53e5f3bd9533922546c554fbf8db20608c99a08103c18d7e924&quot;},&quot;x-ethers&quot;:{&quot;client&quot;:&quot;ethers.js&quot;,&quot;gethFilename&quot;:&quot;UTC--2022-04-17T02-06-38.0Z--84db1f6c4b16cda79f4dc34404445fabe55b97bf&quot;,&quot;mnemonicCounter&quot;:&quot;08d67dd51426a9488c97ed1ca75f3e82&quot;,&quot;mnemonicCiphertext&quot;:&quot;b9c25a345f6bef62ea2fc287c1cc123c&quot;,&quot;path&quot;:&quot;m/44'/60'/0'/0/0&quot;,&quot;locale&quot;:&quot;en&quot;,&quot;version&quot;:&quot;0.1&quot;}}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a4484f65-8db1-4b5b-a210-dc30df2a670f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e3cef352-d13b-4f2d-8679-eef413d33c1e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-3ead45c5-93b9-4f72-b989-047b6300c601&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 지갑복구&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-50ad2ab1-221e-4e25-8ddd-7cb6ca062eb0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지갑 복구는 크게 3가지 방법이 있습니다. 개인키 복구, 키스토어 파일 복구, 니모닉 복구&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-cfa056c1-d8f5-40f4-b0ae-9e7c63bb42a0&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 개인키 복구&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fbc99040-9718-4c56-b7e8-154395cb3df5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-76102c69-7e57-4958-a232-cfc52c2053c3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641787025&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const pk = '0xe6deaed561bbeb9ebc1941b10beb9ff060060d9ea637554abe475eb8f1b13ddc';
const signer = new Wallet(pk)
console.log(signer)

Wallet {
  _isSigner: true,
  _signingKey: [Function (anonymous)],
  _mnemonic: [Function (anonymous)],
  address: '0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17',
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;SE-679868f0-f159-427f-bec5-75d0f22758cb&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 키스토어 파일 복구&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b54f65d9-33d7-4555-84d1-3d2f560f9ada&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a7f3868-61fe-46c3-a9a7-cf4e6d0de121&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641808696&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const password = '123456'
const keystore = {&quot;address&quot;:&quot;84db1f6c4b16cda79f4dc34404445fabe55b97bf&quot;,&quot;id&quot;:&quot;fb49150e-baa5-4325-a3c1-4f8547c118cb&quot;,&quot;version&quot;:3,&quot;Crypto&quot;:{&quot;cipher&quot;:&quot;aes-128-ctr&quot;,&quot;cipherparams&quot;:{&quot;iv&quot;:&quot;39fe92c0b9ccba464e25e63686695f05&quot;},&quot;ciphertext&quot;:&quot;476c18b348830e566c815df1669e281e45777e282494deea857425864b778421&quot;,&quot;kdf&quot;:&quot;scrypt&quot;,&quot;kdfparams&quot;:{&quot;salt&quot;:&quot;a4f06b8ee274dbb763e540cf93d3cded6ceaa43a928381c463767b7e2ee76f33&quot;,&quot;n&quot;:131072,&quot;dklen&quot;:32,&quot;p&quot;:1,&quot;r&quot;:8},&quot;mac&quot;:&quot;3aed307763f9e53e5f3bd9533922546c554fbf8db20608c99a08103c18d7e924&quot;},&quot;x-ethers&quot;:{&quot;client&quot;:&quot;ethers.js&quot;,&quot;gethFilename&quot;:&quot;UTC--2022-04-17T02-06-38.0Z--84db1f6c4b16cda79f4dc34404445fabe55b97bf&quot;,&quot;mnemonicCounter&quot;:&quot;08d67dd51426a9488c97ed1ca75f3e82&quot;,&quot;mnemonicCiphertext&quot;:&quot;b9c25a345f6bef62ea2fc287c1cc123c&quot;,&quot;path&quot;:&quot;m/44'/60'/0'/0/0&quot;,&quot;locale&quot;:&quot;en&quot;,&quot;version&quot;:&quot;0.1&quot;}}
const signer = await Wallet.fromEncryptedJson(JSON.stringify(keystore), password)
console.log(signer)

Wallet {
  _isSigner: true,
  _signingKey: [Function (anonymous)],
  address: '0x84db1f6c4B16CdA79F4dc34404445fabE55B97bF',
  _mnemonic: [Function (anonymous)],
  provider: null
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;SE-9aec2edb-8b4d-40f3-b4a9-b2cd2fb4d0e4&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 니모닉 복구&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-036610c6-d7fa-4b95-8d75-c8a4bc813e9e&quot;&gt;
&lt;pre id=&quot;code_1661641820072&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const mnemonic = &quot;announce room limb pattern dry unit scale effort smooth jazz weasel alcohol&quot;
const signer = Wallet.fromMnemonic(mnemonic)
console.log(signer)

Wallet {
  _isSigner: true,
  _signingKey: [Function (anonymous)],
  address: '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1',
  _mnemonic: [Function (anonymous)],
  provider: null
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-759978b1-27a9-493e-b18a-f38ed56df4f2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-20a9f1bb-20eb-4987-a627-6ab8943bf208&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-50f6ce68-cf33-4689-bf72-89bbc89e6e95&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 서명하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e8ece76a-c13c-4710-b1c6-81a0caab12ab&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서명은 트랜잭션 서명과 메시지 서명이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-253a44f9-156a-45e2-957e-8db10e4a1b87&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 트랜잭션 서명&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2bd014e7-01f3-41b1-a298-63f5cb38aa99&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2c9bcff8-70d2-4a5e-bd39-ffe8e486e4b9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641832711&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const signer = Wallet.createRandom()
const signed = await signer.signTransaction({
  to: '0x6BAE09696c44D0fcF157Cf72b1930632AF435A97',
  from: signer.address,
  value: utils.parseEther('0.1'),
})
console.log(signed)

0xf865808080946bae09696c44d0fcf157cf72b1930632af435a9788016345785d8a0000801ba03d0a131d414b315f5696c93627d188ca8651a31785f3b8d243c82476dd1ede56a00bc31b5e094d9ed1f3b503d96ed125009f03f3ea853d058255dc4484e232f9b5&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;SE-5058ef84-c8f8-4bd3-9613-150f9f490221&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 메시지 서명&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4cb180c9-8239-40a9-b3c5-cd40efb6a3f3&quot;&gt;
&lt;pre id=&quot;code_1661641849752&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const signer = Wallet.createRandom()
const signed = await signer.signMessage(&quot;Hello World&quot;)
console.log(signed)

0xfd5a5ffed4227cd31d374b40f8ba59ed4702a74cbf6d6dca44f971525c71a6df4bb499d48f64012a7a42e13815351cc26d8fb8baef5e9a821de8db3836b84f751b&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8f61e646-384a-442c-b639-c6515d578923&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-98991c61-5fae-4501-921d-8223b7581e36&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Provider 연결&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-d78dc429-402f-4b45-b940-820e961f07dd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션을 발생하기 위해선 Provider를 가지고 있어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9c828c32-b410-4eb0-b598-6c9d3d7b25a4&quot;&gt;
&lt;pre id=&quot;code_1661641860616&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const provider = new providers.JsonRpcProvider(url);

const signer = Wallet.createRandom()
const signed = await signer.signMessage(&quot;Hello World&quot;)

const wallet = signer.connect(provider)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-85598896-8a87-4e9e-94c1-9c48e428f456&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-6deb8bf2-ed50-4de3-8b8e-a750b9e8d9f5&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 이더리움 조회, nonce 조회, 트랜잭션 발생&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5b613a60-f856-4788-8031-704461e4a698&quot;&gt;
&lt;pre id=&quot;code_1661641871295&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;await wallet.getBalance();
 { BigNumber: &quot;42&quot; }

await wallet.getTransactionCount();
 0

// Sending ether
await wallet.sendTransaction(tx)
{
  chainId: 1337,
  confirmations: 0,
  data: '0x',
  from: '0x77C44C0D1D37050e9250415Ee96401B5ac270856',
  gasLimit: { BigNumber: &quot;21000&quot; },
  gasPrice: { BigNumber: &quot;1&quot; },
  hash: '0x5037de21cbba9fbab45b779a8d4e52c610c06bb236f6e38df90a3a69f457aa12',
  nonce: 5,
  r: '0x62623cd493f7dc2a433c5bfa3b0d6802f498220c0ba1e3af0b9851ac8bfe8fe6',
  s: '0x140682e759a02e5a6d68087ff3d531fbdacb9b6ddd637a498c83507cfe347790',
  to: '0x8ba1f109551bD432803012645Ac136ddd64DBA72',
  type: null,
  v: 2709,
  value: { BigNumber: &quot;1000000000000000000&quot; },
  wait: [Function]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7c882f1d-bc06-4608-81fc-db834a2c5edb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8795f2db-b67b-4bd9-9091-0b0b82d63f9c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-3aa8a7f2-4057-4290-9bae-cd09ee447e5a&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● utils&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-b4c37449-ccbc-432a-a725-5f7603a80c61&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;utils는 이더 단위를 바꾸거나 하는 메서드를 제공합니다. 다음 내용은 ethers.utils가 export 한 목록입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f4632b5-7f62-4dee-9a5f-0f54a774b27d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a545d078-3d78-455a-ba6b-e2dd67ad8be5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641891763&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export {
    AbiCoder,
    defaultAbiCoder,

    Fragment,
    ConstructorFragment,
    ErrorFragment,
    EventFragment,
    FunctionFragment,
    ParamType,
    FormatTypes,

    checkResultErrors,
    Result,

    Logger,

    RLP,

    _fetchData,
    fetchJson,
    poll,

    checkProperties,
    deepCopy,
    defineReadOnly,
    getStatic,
    resolveProperties,
    shallowCopy,

    arrayify,

    concat,
    stripZeros,
    zeroPad,

    isBytes,
    isBytesLike,

    defaultPath,
    HDNode,
    SigningKey,

    Interface,

    LogDescription,
    TransactionDescription,

    base58,
    base64,

    hexlify,
    isHexString,
    hexConcat,
    hexStripZeros,
    hexValue,
    hexZeroPad,
    hexDataLength,
    hexDataSlice,

    nameprep,
    _toEscapedUtf8String,
    toUtf8Bytes,
    toUtf8CodePoints,
    toUtf8String,
    Utf8ErrorFuncs,

    formatBytes32String,
    parseBytes32String,

    dnsEncode,
    hashMessage,
    namehash,
    isValidName,
    id,

    _TypedDataEncoder,

    getAddress,
    getIcapAddress,
    getContractAddress,
    getCreate2Address,
    isAddress,

    formatEther,
    parseEther,

    formatUnits,
    parseUnits,

    commify,

    computeHmac,
    keccak256,
    ripemd160,
    sha256,
    sha512,

    randomBytes,
    shuffled,

    solidityPack,
    solidityKeccak256,
    soliditySha256,

    splitSignature,
    joinSignature,

    accessListify,
    parseTransaction,
    serializeTransaction,
    TransactionTypes,

    getJsonWalletAddress,

    computeAddress,
    recoverAddress,

    computePublicKey,
    recoverPublicKey,

    verifyMessage,
    verifyTypedData,

    getAccountPath,
    mnemonicToEntropy,
    entropyToMnemonic,
    isValidMnemonic,
    mnemonicToSeed,


    ////////////////////////
    // Enums

    SupportedAlgorithm,

    UnicodeNormalizationForm,
    Utf8ErrorReason,

    ////////////////////////
    // Types

    Bytes,
    BytesLike,
    Hexable,

    AccessList,
    AccessListish,
    UnsignedTransaction,

    CoerceFunc,

    Indexed,

    Mnemonic,

    Deferrable,

    Utf8ErrorFunc,

    ConnectionInfo,
    OnceBlockable,
    OncePollable,
    PollOptions,
    FetchJsonResponse,

    EncryptOptions,
    ProgressCallback
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;SE-6244a256-db3d-425e-99f4-1b047bfb8c6b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 단위변경&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e076b0b4-61e4-4057-ad97-71997b8c0c6a&quot;&gt;
&lt;pre id=&quot;code_1661641910234&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;balance = await provider.getBalance(&quot;ethers.eth&quot;)
{ BigNumber: &quot;82826475815887608&quot; }

// wei -&amp;gt; ether
utils.formatEther(balance)
'0.082826475815887608'

// ether -&amp;gt; wei
utils.parseEther(&quot;1.0&quot;)
{ BigNumber: &quot;1000000000000000000&quot; }

// 특정 단위적용
utils.parseUnits('5', 'gwei')
BigNumber { _hex: '0x012a05f200', _isBigNumber: true }
0.000000005 Ether&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2255aea6-cfd4-44b7-b5a1-bb3d4bd5379f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-bc3b8a29-8753-4e2f-9b84-ddc78551fe1f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 주소 유효성 검사&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0654faa2-6296-401f-a5a2-5e6959fedb45&quot;&gt;
&lt;pre id=&quot;code_1661641916073&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(utils.isAddress('0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17'))
console.log(utils.isAddress('0x86B6acf21e6F4aE6bAdFDBc4F5D00741823d17'))

true
false&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f024b03a-aeab-4ffc-b366-3e5299af82cb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 id=&quot;SE-df2521e2-4b8d-4607-9566-9fd7e2122fde&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● Contract&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-1b674656-e820-4d5d-87dd-8eb0593a9a5b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Contract는 트랜잭션을 발생하고 컨트랙트에서 관리하는 상태를 조회할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0d245d43-c516-4d8f-84bf-a92b1992a946&quot;&gt;
&lt;pre id=&quot;code_1661641928577&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity 0.8.13;
 
contract test {
  uint public a = 10;

  event onEvent1(uint indexed a);
  event onEvent2(uint a);
  
  function event1() public {
    emit onEvent1(1);
  }
  
  function event2() public {
    emit onEvent2(2);
  }

  function getA() view public returns (uint) {
    return a;
  }

  function setA(uint _a) public {
    a = _a;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a48f310c-c749-4403-9de2-f900c9eefbeb&quot;&gt;
&lt;pre id=&quot;code_1661641935747&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CA: 0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-55b50d9d-8513-47c9-b8bb-06894507e69f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wZblb/btrKGRLV32z/3wb3ORZHeL6WkqIsTePuH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wZblb/btrKGRLV32z/3wb3ORZHeL6WkqIsTePuH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wZblb/btrKGRLV32z/3wb3ORZHeL6WkqIsTePuH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwZblb%2FbtrKGRLV32z%2F3wb3ORZHeL6WkqIsTePuH1%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;773&quot; height=&quot;594&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9955fa9d-2345-4ae1-b3fb-d680ee3afb36&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-63895cf1-9b51-4ae6-86ad-c32ab5780eda&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 컨트랙트 객체 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ddb743fc-f683-4467-bb51-296f03490549&quot;&gt;
&lt;pre id=&quot;code_1661641955192&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const ABI = [
  {
    &quot;inputs&quot;: [],
    &quot;name&quot;: &quot;event1&quot;,
    &quot;outputs&quot;: [],
    &quot;stateMutability&quot;: &quot;nonpayable&quot;,
    &quot;type&quot;: &quot;function&quot;
  },
  {
    &quot;inputs&quot;: [],
    &quot;name&quot;: &quot;event2&quot;,
    &quot;outputs&quot;: [],
    &quot;stateMutability&quot;: &quot;nonpayable&quot;,
    &quot;type&quot;: &quot;function&quot;
  },
  {
    &quot;anonymous&quot;: false,
    &quot;inputs&quot;: [
      {
        &quot;indexed&quot;: true,
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;a&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;name&quot;: &quot;onEvent1&quot;,
    &quot;type&quot;: &quot;event&quot;
  },
  {
    &quot;anonymous&quot;: false,
    &quot;inputs&quot;: [
      {
        &quot;indexed&quot;: false,
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;a&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;name&quot;: &quot;onEvent2&quot;,
    &quot;type&quot;: &quot;event&quot;
  },
  {
    &quot;inputs&quot;: [
      {
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;_a&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;name&quot;: &quot;setA&quot;,
    &quot;outputs&quot;: [],
    &quot;stateMutability&quot;: &quot;nonpayable&quot;,
    &quot;type&quot;: &quot;function&quot;
  },
  {
    &quot;inputs&quot;: [],
    &quot;name&quot;: &quot;a&quot;,
    &quot;outputs&quot;: [
      {
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;stateMutability&quot;: &quot;view&quot;,
    &quot;type&quot;: &quot;function&quot;
  },
  {
    &quot;inputs&quot;: [],
    &quot;name&quot;: &quot;getA&quot;,
    &quot;outputs&quot;: [
      {
        &quot;internalType&quot;: &quot;uint256&quot;,
        &quot;name&quot;: &quot;&quot;,
        &quot;type&quot;: &quot;uint256&quot;
      }
    ],
    &quot;stateMutability&quot;: &quot;view&quot;,
    &quot;type&quot;: &quot;function&quot;
  }
];
const signer = new Wallet(
  '0xe6deaed561bbeb9ebc1941b10beb9ff060060d9ea637554abe475eb8f1b13ddc',
  provider
)
const contract = new Contract(
  '0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0',
  ABI,
  signer
)
const rst0 = await contract.getA();
const rst1 = await contract.a();
console.log(rst0)
console.log(rst1)

BigNumber { _hex: '0x0a', _isBigNumber: true }
BigNumber { _hex: '0x0a', _isBigNumber: true }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-53ebe188-c776-4014-975b-b00896ace3d1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b4eb8f08-d4e4-4294-bce3-4def213bf4d3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ethers는 ABI를 다음과 같이 정의할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8ed0522f-8210-4e79-818c-fa6373caebb6&quot;&gt;
&lt;pre id=&quot;code_1661641964566&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const ABI = [
  'event onEvent1(uint indexed a)',
  'event onEvent2(uint a)',
  'function getA() view public returns (uint)',
  'function a() view public returns (uint)',
  'function setA(uint _a) public'
];
const signer = new Wallet(
  '0xe6deaed561bbeb9ebc1941b10beb9ff060060d9ea637554abe475eb8f1b13ddc',
  provider
)
const contract = new Contract(
  '0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0',
  ABI,
  signer
)
const rst0 = await contract.getA();
const rst1 = await contract.a();
console.log(rst0)
console.log(rst1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3a0e8971-67e0-4d1d-82dd-fb6b9020b30c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c3fb0ee9-2fde-470a-8ea4-d3077e7d84de&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Contract 객체를 만들 때 signer가 아니라 provider를 전달할 수 있는데 signer(Wallet)를 전달하지 않으면 읽기전용입니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-0bc5c567-0518-4c95-9bc8-76b3b94b70e0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 발생&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ef6ac8aa-e3a0-4317-98a2-491dcc1c959b&quot;&gt;
&lt;pre id=&quot;code_1661641981593&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const ABI = [
  'event onEvent1(uint indexed a)',
  'event onEvent2(uint a)',
  'function getA() view public returns (uint)',
  'function a() view public returns (uint)',
  'function setA(uint _a) public'
];
const signer = new Wallet(
  '0xe6deaed561bbeb9ebc1941b10beb9ff060060d9ea637554abe475eb8f1b13ddc',
  provider
)
const contract = new Contract(
  '0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0',
  ABI,
  signer
)
const rst0 = await contract.setA(123);
console.log(rst0)

const rst1 = await contract.a();
console.log(rst1)

{
  nonce: 10,
  gasPrice: BigNumber { _hex: '0x04a817c800', _isBigNumber: true },
  gasLimit: BigNumber { _hex: '0x682c', _isBigNumber: true },
  to: '0xFc0D07749d61479727d5EE0743D4d03f4C5Eb3B0',
  value: BigNumber { _hex: '0x00', _isBigNumber: true },
  data: '0xee919d50000000000000000000000000000000000000000000000000000000000000007b',
  chainId: 1337,
  v: 2709,
  r: '0x229c8022469d2a4cf0123e10b6b109b038545619db3f861ee28859d1d492fd34',
  s: '0x00817868e24ce66cc00ebfbe1f2a86fabba40d43bebafc15f78a73497a02d680',
  from: '0x86B6acf21e6F4aE60bbAdFDBc4F5D00741823d17',
  hash: '0xb09ab043d685e55312f95d786c37f81eb8afb70fa8fe9e63894b0dcc96cd76e9',
  type: null,
  confirmations: 0,
  wait: [Function (anonymous)]
}
BigNumber { _hex: '0x7b', _isBigNumber: true }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4ab418de-7e9d-4803-8eb1-b310dcf8f194&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-544901fe-774b-41f2-971e-6b99bfdbcebb&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 이벤트 수신&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4ea53e75-33ac-4a8d-9f55-b2418c18029a&quot;&gt;
&lt;pre id=&quot;code_1661641991057&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contract.on('onEvent1', (a) =&amp;gt; {
  console.log(a)
})
contract.on('onEvent2', (a) =&amp;gt; {
  console.log(a)
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2ca122b1-9257-4130-b7e1-1a6fe0c5f8c5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vMb1y/btrKHc97Xo6/79tcgMM9KrHz2Q5SWgcRb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vMb1y/btrKHc97Xo6/79tcgMM9KrHz2Q5SWgcRb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vMb1y/btrKHc97Xo6/79tcgMM9KrHz2Q5SWgcRb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvMb1y%2FbtrKHc97Xo6%2F79tcgMM9KrHz2Q5SWgcRb0%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;773&quot; height=&quot;594&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-211672ca-8b91-4da2-98cd-95ab80fea89a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-06c0e092-8bf8-405a-8eda-5b5eb364e009&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이벤트를 발생하는 함수를 호출하면 각각의 이벤트 리스터를 호출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>Ethereum</category>
      <category>ethers</category>
      <category>ethers.js</category>
      <category>solidity</category>
      <category>web3</category>
      <category>web3.js</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/87</guid>
      <comments>https://meongae.tistory.com/87#entry87comment</comments>
      <pubDate>Sun, 28 Aug 2022 08:13:28 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] ERC20 만들 때 주의할 점 - symbol, decimals</title>
      <link>https://meongae.tistory.com/86</link>
      <description>&lt;div id=&quot;SE-ac4d1eba-7e25-4742-811d-0463f60c6074&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-08032b1f-d9c6-44d6-a7e1-cdbeb16e598a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ERC20의 인터페이스 중 symbol이 존재합니다. ERC20을 배포하면서 symbol을 초기화하게 되는데 이때 주의할 점이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f7a817b7-ea3a-4de8-b9f4-734626f498be&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4a94c66d-45b8-44e5-9fe2-eb4174cd5176&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기본적으로 symbol 자체는 길이가 정해져있지는 않지만 메타마스크를 기준으로는 토큰 기호가 11자리가 넘어가지 않는것을 권장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-93dec3b0-ba19-46f4-ba04-488aa0e325bc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;601&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bb3jU8/btrKGp292Dz/0BRdyrJDQwld1QLiYBz3H1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bb3jU8/btrKGp292Dz/0BRdyrJDQwld1QLiYBz3H1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bb3jU8/btrKGp292Dz/0BRdyrJDQwld1QLiYBz3H1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbb3jU8%2FbtrKGp292Dz%2F0BRdyrJDQwld1QLiYBz3H1%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;357&quot; height=&quot;601&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;601&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6561964e-2998-4749-a473-44d8f5e6412c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2141533b-efa0-4122-a12f-2de549bf8019&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 또 하나 궁금증이 생겨서 테스트를 진행해보았습니다. 한글로 설정한다면?&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-04f5579d-4e35-4f1d-8eaa-d474bbb1483a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgUl4K/btrKLfR1aDY/aTJcBEYX2MOtQeDKKV6ebK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgUl4K/btrKLfR1aDY/aTJcBEYX2MOtQeDKKV6ebK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgUl4K/btrKLfR1aDY/aTJcBEYX2MOtQeDKKV6ebK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgUl4K%2FbtrKLfR1aDY%2FaTJcBEYX2MOtQeDKKV6ebK%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;357&quot; height=&quot;602&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-af4a2baa-8391-4b44-bff2-148be16a49cd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d92322ea-a4f5-4574-a09c-e39f890ea2bb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다행히 한글은 정상적으로 동작합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-69db0555-5454-4510-bd1b-56eea2de5d2a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d1a31f5f-71d8-4377-82f2-e8385fbfc04a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막으로 토큰 십진수로 표시되어 있는 부분은 decimals인데 이 부분은 UINT8이 표준이므로 0~255까지 256개의 데이터를 허용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>dicimals</category>
      <category>erc</category>
      <category>ERC20</category>
      <category>strandard</category>
      <category>symbiol</category>
      <category>symbol</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/86</guid>
      <comments>https://meongae.tistory.com/86#entry86comment</comments>
      <pubDate>Sun, 28 Aug 2022 08:02:48 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] gas와 관련된 에러</title>
      <link>https://meongae.tistory.com/85</link>
      <description>&lt;div id=&quot;SE-0e403b3d-1f3e-45bd-b033-3fddb694dff7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4762c04a-e77a-4724-8fe2-24a142b11c05&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;안녕하세요 멍개입니다. 이번글에서는 이더리움에서 트랜잭션 실행할 때 발생할 수 있는 gas 에러를 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6f019c4e-4a86-4f94-b1bb-c35ab6312ad0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a8887546-9ef0-4834-babe-70a90f94c95d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;▶ out of gas&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c95840c0-8f2f-4d3d-b878-e2dec9b8fddc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;▶ exceeds block gas limit&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5accc478-8382-4621-9b81-e49a79aaa89c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;▶ gasLimit is too low&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-03ab26ab-1f95-49e3-9952-16c5cf4deb58&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;▶ base fee exceeds gas limit&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1691455f-1907-44a7-b987-c79dfbe99265&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c4f285c0-dd1b-458a-b402-594a44d95728&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 네트워크 실행&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f3513e3c-b177-42d0-85ce-b9ff9686582a&quot;&gt;
&lt;pre id=&quot;code_1661641175566&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ganache-cli&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d73c28b5-e878-4ef0-a5af-aa21dec7a513&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-6619d9be-14cb-4a4e-b1f1-24758ef17839&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; out of gas&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-4cb2ccd5-b57a-4130-b545-19871090f490&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션을 실행하여 상태를 변경할 때 실행된 코드에 따라 가스를 소모합니다. 이때 트랜잭션엔 어느정도 코드 실행을 할지 결정하는 gas를 설정할 수 있는데 설정된 값보다 더 많은 코드를 실행하려고 할 때 발생하는 에러입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f416fd4-0a6f-4cf2-9155-3f38253f7e46&quot;&gt;
&lt;pre id=&quot;code_1661641190220&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
 
contract Mung {
 string public text;
 constructor(string memory _text) {
   text = _text;
 }
  function setText(string memory _text) public{
   text = _text;
 }
  function say() public view returns(string memory){
   return text;
 }
 
 function errorOccur(uint a) public pure returns (uint) {
   require(a == 0, &quot;hello world error&quot;);
   return a;
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-60344069-b50b-4b1e-8afa-6e5f3a8bb6c7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d1ce7e43-aab7-4ffe-8d03-21ea27f874d2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 컨트랙트 코드를 배포하는 트랜잭션을 만들어보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7f2fd5dd-230a-4e48-b194-c6b755924f64&quot;&gt;
&lt;pre id=&quot;code_1661641202507&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Web3 = require('web3');
let web3 = new Web3(new Web3.providers.HttpProvider(&quot;http://localhost:8545&quot;));

async function main() {
 const from = '0x42aBb1C1b24fC723634547AcC6fa2478fD0EBe44'; // ganache-cli에서 생성한 주소
 var mungContract = new web3.eth.Contract([
	{
		&quot;inputs&quot;: [
			{
				&quot;internalType&quot;: &quot;string&quot;,
				&quot;name&quot;: &quot;_text&quot;,
				&quot;type&quot;: &quot;string&quot;
			}
		],
		&quot;stateMutability&quot;: &quot;nonpayable&quot;,
		&quot;type&quot;: &quot;constructor&quot;
	},
	{
		&quot;inputs&quot;: [
			{
				&quot;internalType&quot;: &quot;uint256&quot;,
				&quot;name&quot;: &quot;a&quot;,
				&quot;type&quot;: &quot;uint256&quot;
			}
		],
		&quot;name&quot;: &quot;errorOccur&quot;,
		&quot;outputs&quot;: [
			{
				&quot;internalType&quot;: &quot;uint256&quot;,
				&quot;name&quot;: &quot;&quot;,
				&quot;type&quot;: &quot;uint256&quot;
			}
		],
		&quot;stateMutability&quot;: &quot;pure&quot;,
		&quot;type&quot;: &quot;function&quot;
	},
	{
		&quot;inputs&quot;: [],
		&quot;name&quot;: &quot;say&quot;,
		&quot;outputs&quot;: [
			{
				&quot;internalType&quot;: &quot;string&quot;,
				&quot;name&quot;: &quot;&quot;,
				&quot;type&quot;: &quot;string&quot;
			}
		],
		&quot;stateMutability&quot;: &quot;view&quot;,
		&quot;type&quot;: &quot;function&quot;
	},
	{
		&quot;inputs&quot;: [
			{
				&quot;internalType&quot;: &quot;string&quot;,
				&quot;name&quot;: &quot;_text&quot;,
				&quot;type&quot;: &quot;string&quot;
			}
		],
		&quot;name&quot;: &quot;setText&quot;,
		&quot;outputs&quot;: [],
		&quot;stateMutability&quot;: &quot;nonpayable&quot;,
		&quot;type&quot;: &quot;function&quot;
	},
	{
		&quot;inputs&quot;: [],
		&quot;name&quot;: &quot;text&quot;,
		&quot;outputs&quot;: [
			{
				&quot;internalType&quot;: &quot;string&quot;,
				&quot;name&quot;: &quot;&quot;,
				&quot;type&quot;: &quot;string&quot;
			}
		],
		&quot;stateMutability&quot;: &quot;view&quot;,
		&quot;type&quot;: &quot;function&quot;
	}
]); // remix에서 ABI 복사한 값을 인자로 전달
 var mung = mungContract.deploy({
     data: '',  // remix에서 bytecode.object 복사한 값
     arguments: ['test'] // 생성자에 전달할 값
 }).send({
     from: from,
     gas: '100000' 
   }, function (err, contract){
     console.log(err, contract);
 })
}

main();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c49df086-5e94-4288-b901-70b5ac8139d7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-752d677e-6adb-4f6f-84ba-ad0615f33a40&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 data엔 컴파일 결과인 바이트 코드를 넣어줍니다. gas가 100,000으로 설정되어 있습니다. 해당 코드를 실행하면 다음과 같은 에러 메시지를 출력합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d455ed7c-ca22-428f-a599-12336e23df19&quot;&gt;
&lt;pre id=&quot;code_1661641213215&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error: Returned error: VM Exception while processing transaction: out of gas&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7d851584-cb4d-4cf9-b51e-27409e3c1044&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-17850d2a-eb4e-4e0c-9c77-1df0b0f28bdc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실행될 코드가 가스를 초과하서 발생한 에러입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-43e10dfc-b912-46eb-b610-1648e512b55e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e64546c9-1534-4042-9b90-1546dcaee02b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 컨트랙트 코드는 4,700,000 정도면 충분히 배포 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-d4539698-d7dd-4971-a568-15e505083a44&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Exceeds block gas limit&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-963e160c-318f-499f-83b6-8ee44762029e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실행할 트랜잭션은 블록에 포함되어집니다. 이때 블록이 포함하고 있는 트랜잭션의 모든 가스합을 가지고 있는데 이 값이 특정값을 넘어가면 발생하는 에러가 Exceeds block gas limit 입니다. 앞의 코드에서 gas를 매우 높여서 실행하면 다음과 같은 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-16dad7b5-813b-456d-9ae5-e3fb4c82fdd6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641223243&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error: Returned error: Exceeds block gas limit&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; base fee exceeds gas limit&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eb2fed4a-6d5e-4039-a008-b74baf6d64c3&quot;&gt;
&lt;p id=&quot;SE-5e7a1583-aaa0-4fbf-9495-f541938c9121&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 에러는 스마트 컨트랙트를 배포하거나 실행하는 트랜잭션을 실행할 떄 최소 기준 가스보다 gas의 한도치를 너무 낮게 설정할 경우 발생하는 에러입니다.(이더리움을 전송하는 트랜잭션은 해당 에러가 발생하지 않습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7ab74545-2ca9-4ef3-ac01-15a37cfeeb7f&quot;&gt;
&lt;pre id=&quot;code_1661641249251&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Returned error: base fee exceeds gas limit&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3aa0beb0-757a-4c11-aeac-7723cd52b07c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-60f41ca0-03a2-4a1b-a323-6853019a5cfc&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; gasLimit is too low&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-1865a46b-fe4e-4e02-a38c-7daab10acf9e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움 전송 트랜잭션은 gasLimit이 21,000으로 고정되어 있습니다. 만약 해당 수치보다 낮은 수치로 트랜잭션을 발생하면 gasLimit is too low 에러가 발생합니다. 기준치는 초과하지만 21000보다 작을 때 해당 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-de858a6f-4218-401d-9307-cd54de8f354f&quot;&gt;
&lt;pre id=&quot;code_1661641261196&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Web3 = require('web3');
let web3 = new Web3(new Web3.providers.HttpProvider(&quot;http://localhost:8545&quot;));

async function main() {
  const from = '0x42aBb1C1b24fC723634547AcC6fa2478fD0EBe44';
  const pk = '0xa960a13e39802345fb5c0e4bce81aed3e94ca4fccf3f17e148fd68beece8fe08' // from에 대응하는 privateKey를 넣어준다
  const to = '0x6c6117196b7c4D4986a1DA1234C003DaE54F44C9' 
  const tx = {
	from,
	to,
	gas: 21000, // gasLimit
	gasPrice: '21000000000', // 해당 값은 그대로 입력 합니다.
	value: '1000000000000000' // 원하는 이더전송 수량을 입력합니다.
  }
  const account = web3.eth.accounts.privateKeyToAccount(pk) // 개인키를 account 객체로 복구
  const signedTx = await account.signTransaction(tx) // 개인키로 트랜잭션 서명
  const sentTx = await web3.eth.sendSignedTransaction(
	signedTx.raw || signedTx.rawTransaction
  ); // 서명된 트랜잭션 이더리움 노드로 전송
  console.log(sentTx);
}
main();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f3fd0004-9300-4544-9ce6-5cf228d875c6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a021599b-b084-4e51-a00c-c353419fbe58&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;from, pk, to는 적절히 넣어줍니다. 해당 코드를 실행하면 정상적으로 동작합니다. gas를 다음과 같이 수정한 후 실행하면 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cf4e88e1-c53d-4391-a7e3-50fdef0a6788&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-147c6e32-99f6-4332-b290-21c14bfa5e4d&quot;&gt;
&lt;pre id=&quot;code_1661641267851&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const tx = {
    from,
    to,
    gas: 2100, // 해당 값은 그대로 입력 합니다.
    gasPrice: '21000000000', // 해당 값은 그대로 입력 합니다.
    value: '1000000000000000' // 원하는 이더전송 수량을 입력합니다.
  }​&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641275335&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error: Signer Error: Signer Error:  gasLimit is too low. given 2100, need at least 21000.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8afc08a1-6be2-436a-865c-cabbe93eaae0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c8017596-758c-4d9e-896b-6898217962cf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 번째로 스마트 컨트랙트를 호출 할 때 21,000보다 낮게 설정해도 해당 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6c6140ef-fc8e-4561-8783-0e586906b8df&quot;&gt;
&lt;pre id=&quot;code_1661641283083&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
 
contract Mung {
 string public text;
 constructor(string memory _text) {
   text = _text;
 }
  function setText(string memory _text) public{
   text = _text;
 }
  function say() public view returns(string memory){
   return text;
 }
 
 function errorOccur(uint a) public pure returns (uint) {
   require(a == 0, &quot;hello world error&quot;);
   return a;
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-97c4dad8-3a2c-432e-9e69-32465209c818&quot;&gt;
&lt;pre id=&quot;code_1661641291244&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Web3 = require('web3');
let web3 = new Web3(new Web3.providers.HttpProvider(&quot;http://localhost:8545&quot;));
async function main() {
  const CA = &quot;0xaF3DE8794C26363c04A313Bc0cf8A01915017B21&quot; // 배포한 스마트 컨트랙트 주소
  const from = '0x42aBb1C1b24fC723634547AcC6fa2478fD0EBe44';
  const pk = '0xa960a13e39802345fb5c0e4bce81aed3e94ca4fccf3f17e148fd68beece8fe08' // from에 대응하는 privateKey를 넣어준다어준다
  const ABI = [
    {
      &quot;inputs&quot;: [
        {
          &quot;internalType&quot;: &quot;string&quot;,
          &quot;name&quot;: &quot;_text&quot;,
          &quot;type&quot;: &quot;string&quot;
        }
      ],
      &quot;stateMutability&quot;: &quot;nonpayable&quot;,
      &quot;type&quot;: &quot;constructor&quot;
    },
    {
      &quot;inputs&quot;: [
        {
          &quot;internalType&quot;: &quot;uint256&quot;,
          &quot;name&quot;: &quot;a&quot;,
          &quot;type&quot;: &quot;uint256&quot;
        }
      ],
      &quot;name&quot;: &quot;errorOccur&quot;,
      &quot;outputs&quot;: [
        {
          &quot;internalType&quot;: &quot;uint256&quot;,
          &quot;name&quot;: &quot;&quot;,
          &quot;type&quot;: &quot;uint256&quot;
        }
      ],
      &quot;stateMutability&quot;: &quot;pure&quot;,
      &quot;type&quot;: &quot;function&quot;
    },
    {
      &quot;inputs&quot;: [],
      &quot;name&quot;: &quot;say&quot;,
      &quot;outputs&quot;: [
        {
          &quot;internalType&quot;: &quot;string&quot;,
          &quot;name&quot;: &quot;&quot;,
          &quot;type&quot;: &quot;string&quot;
        }
      ],
      &quot;stateMutability&quot;: &quot;view&quot;,
      &quot;type&quot;: &quot;function&quot;
    },
    {
      &quot;inputs&quot;: [
        {
          &quot;internalType&quot;: &quot;string&quot;,
          &quot;name&quot;: &quot;_text&quot;,
          &quot;type&quot;: &quot;string&quot;
        }
      ],
      &quot;name&quot;: &quot;setText&quot;,
      &quot;outputs&quot;: [],
      &quot;stateMutability&quot;: &quot;nonpayable&quot;,
      &quot;type&quot;: &quot;function&quot;
    },
    {
      &quot;inputs&quot;: [],
      &quot;name&quot;: &quot;text&quot;,
      &quot;outputs&quot;: [
        {
          &quot;internalType&quot;: &quot;string&quot;,
          &quot;name&quot;: &quot;&quot;,
          &quot;type&quot;: &quot;string&quot;
        }
      ],
      &quot;stateMutability&quot;: &quot;view&quot;,
      &quot;type&quot;: &quot;function&quot;
    }
  ]; // remix 또는 트러플 컴파일 결과에서 ABI 복사하여 넣어준다.
 
  // 스마트 컨트랙트 객체 생성
  let Contract = new web3.eth.Contract(ABI, CA); 
 
  // 스마트 컨트랙트에 정의한 함수 실행
  let bytedata = await Contract.methods.setText(&quot;test&quot;).encodeABI(); 
  console.log(bytedata);
 
  const tx = {
     from,
     to: CA,
     gas: 1000, // 해당 수치는 그대로 입력합니다.
     gasPrice: '21000000000', // 해당 수치는 그대로 입력합니다.
     data: bytedata
  }
 
  const account = web3.eth.accounts.privateKeyToAccount(pk)
  const signedTx = await account.signTransaction(tx)
  const sentTx = await web3.eth.sendSignedTransaction(signedTx.raw || signedTx.rawTransaction);
  console.log(sentTx);
}
 
main();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a53e7029-0f02-43f6-bad3-c5dfc689875c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-57a02c24-be39-4ae4-b8f6-f91e93ed7c79&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;gas를 1000으로 매우 낮게 주었습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-159e8412-baef-4d47-bb24-9806c6a6fe06&quot;&gt;
&lt;pre id=&quot;code_1661641298203&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error: Signer Error: Signer Error:  gasLimit is too low. given 1000, need at least 21520.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-94a79e46-db62-4afa-a0cc-67b85025ddc5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-63af7a71-5b7c-46e6-8937-7f8de1ba32c1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움 전송할때와 유사한 에러를 출력합니다. 여시거 21520이 필요하다고 하는데 제가 찾은 최소값은 26788입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>Ethereum</category>
      <category>gas</category>
      <category>가스</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/85</guid>
      <comments>https://meongae.tistory.com/85#entry85comment</comments>
      <pubDate>Sun, 28 Aug 2022 08:01:52 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] EIP, ERC 그것을 파악해보자</title>
      <link>https://meongae.tistory.com/84</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.naver.com/pjt3591oo/222597931496&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.naver.com/pjt3591oo/222597931496&lt;/a&gt;&lt;/p&gt;</description>
      <category>블록체인</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/84</guid>
      <comments>https://meongae.tistory.com/84#entry84comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:58:59 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] hardhat을 이용하여 스마트 컨트랙트 개발하기</title>
      <link>https://meongae.tistory.com/83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;지난 시간에 truffle을 이용하여 스마트 컨트랙트 개발하는 방법을 소개했습니다.&lt;/span&gt;&lt;/p&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;a href=&quot;https://meongae.tistory.com/81&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.28 - [블록체인] - [ethereum] truffle을 이용하여 스마트 컨트랙트 개발하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661640517332&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[ethereum] truffle을 이용하여 스마트 컨트랙트 개발하기&quot; data-og-description=&quot;ruffle을 이용하여 스마트 컨트랙트를 개발하는 방법을 다룹니다. ● 셋업 $ npm install -g truffle &amp;middot; 프로젝트 생성 $ mkdir dapp $ cd dapp $ truffle init init 명령어를 사용하여 truffle 기반의 프로젝트를..&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/81&quot; data-og-url=&quot;https://meongae.tistory.com/81&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cyyGCg/hyPAow9hUW/MKGbRbujK6fHgfhgK41B1k/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bcN5Sd/hyPBQlfPXT/GdWH7pqHi9Ewq8O5ofDYf1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/uLVDr/hyPAvQyfmr/Yw05EBIoQPmYG6ecHttFF0/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/81&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/81&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cyyGCg/hyPAow9hUW/MKGbRbujK6fHgfhgK41B1k/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bcN5Sd/hyPBQlfPXT/GdWH7pqHi9Ewq8O5ofDYf1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/uLVDr/hyPAvQyfmr/Yw05EBIoQPmYG6ecHttFF0/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[ethereum] truffle을 이용하여 스마트 컨트랙트 개발하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;ruffle을 이용하여 스마트 컨트랙트를 개발하는 방법을 다룹니다. ● 셋업 $ npm install -g truffle &amp;middot; 프로젝트 생성 $ mkdir dapp $ cd dapp $ truffle init init 명령어를 사용하여 truffle 기반의 프로젝트를..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;추가적으로 출금패턴(withdrawals patterns)을 truffle을 활용하여 다뤄보기도 했습니다.&lt;/span&gt;&lt;/p&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;a href=&quot;https://meongae.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.28 - [블록체인] - [ethereum] solidity withdrawals pattern(출금패턴)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661640525742&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[ethereum] solidity withdrawals pattern(출금패턴)&quot; data-og-description=&quot;solidity에서 출금패턴을 다뤄보겠습니다. 제가 이 포스팅을 위해 삽질한 과정을 보고 싶다면 여기로 오시면 되겠습니다. 약 2시간 30분동안 삽질을 하였습니다. ☞ 목차 1. 준비 2. 입/출금 가능한 &quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/82&quot; data-og-url=&quot;https://meongae.tistory.com/82&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/v6DgT/hyPAyme4ip/HkH0UXs0cOEEKcLnl5msvK/img.png?width=773&amp;amp;height=602&amp;amp;face=0_0_773_602,https://scrap.kakaocdn.net/dn/IuMKY/hyPBJGrRny/o8OyjWWyvKQaFXkdvA8LPk/img.png?width=773&amp;amp;height=602&amp;amp;face=0_0_773_602,https://scrap.kakaocdn.net/dn/pZf0Y/hyPAr1GV7s/v9Wuj45ftGnvAKEdPFxynK/img.png?width=773&amp;amp;height=602&amp;amp;face=0_0_773_602&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/82&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/82&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/v6DgT/hyPAyme4ip/HkH0UXs0cOEEKcLnl5msvK/img.png?width=773&amp;amp;height=602&amp;amp;face=0_0_773_602,https://scrap.kakaocdn.net/dn/IuMKY/hyPBJGrRny/o8OyjWWyvKQaFXkdvA8LPk/img.png?width=773&amp;amp;height=602&amp;amp;face=0_0_773_602,https://scrap.kakaocdn.net/dn/pZf0Y/hyPAr1GV7s/v9Wuj45ftGnvAKEdPFxynK/img.png?width=773&amp;amp;height=602&amp;amp;face=0_0_773_602');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[ethereum] solidity withdrawals pattern(출금패턴)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;solidity에서 출금패턴을 다뤄보겠습니다. 제가 이 포스팅을 위해 삽질한 과정을 보고 싶다면 여기로 오시면 되겠습니다. 약 2시간 30분동안 삽질을 하였습니다. ☞ 목차 1. 준비 2. 입/출금 가능한&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;이번글에서는 truffle을 대체할수 있는 hardhat을 이용하여 스마트 컨트랙트 개발하는 방법을 소개합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;● 셋업&lt;/b&gt;&lt;/p&gt;
&lt;div id=&quot;SE-1cfff76b-310a-42f3-979f-75b50b0f7379&quot;&gt;
&lt;p id=&quot;SE-89ba4939-881d-452f-9a93-d866b9addbe4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;hardhat을 이용하여 개발할 수 있는 환경을 구축합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-43ee3630-78ca-4a21-aef9-06c20fef7d7d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 프로젝트 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e24a8701-1f48-4ce8-a510-f9881c899f41&quot;&gt;
&lt;pre id=&quot;code_1661640566855&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir hardhat-test
$ cd hardhat-test&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-75616299-eb7e-4215-9613-7430f19a0831&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661640577125&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save-dev hardhat&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d30a05c9-99e1-4bee-b19a-01a732356bb6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661640585373&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx hardhat&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-850add33-028e-4cb3-8d08-2a8e595b579d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czwUUt/btrKHxMV8Vj/8XDaGHAR8dJO7BguadfKVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czwUUt/btrKHxMV8Vj/8XDaGHAR8dJO7BguadfKVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czwUUt/btrKHxMV8Vj/8XDaGHAR8dJO7BguadfKVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczwUUt%2FbtrKHxMV8Vj%2F8XDaGHAR8dJO7BguadfKVk%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;650&quot; height=&quot;339&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bb31e603-829f-4d9a-a8dc-eccf4043f414&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b4785ebd-c5e1-42aa-97c2-3969df6444e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;어떤 형태의 프로젝트를 생성할 지 묻습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a20f43a3-a45c-49b1-8670-b297e40b6fb2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b0d09ec0-afb2-439b-8e2b-471921cfda4a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;저는 여기서 세 번째 Create an advanced sample project that uses TypeScript를 선택하도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-70107721-6fc2-499e-97a7-9a4e6e1eeee8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;선택을 하면 3가지를 더 묻습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c5a58afc-7357-4647-b306-6904c334bd1b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cslUlz/btrKH0afAKN/SPd7X99zKYXnGgt1b2JgA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cslUlz/btrKH0afAKN/SPd7X99zKYXnGgt1b2JgA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cslUlz/btrKH0afAKN/SPd7X99zKYXnGgt1b2JgA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcslUlz%2FbtrKH0afAKN%2FSPd7X99zKYXnGgt1b2JgA1%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;650&quot; height=&quot;339&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3fa48be6-8dc7-4d24-840e-80450229a8f5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-615f9eca-60ab-4219-9e9a-4a5f1b9de883&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;프로젝트 루트 경로&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cf83375a-5d68-4ca9-8dec-d053bb5c2092&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YpIQh/btrKGw86i6Z/RJXkwmtwHNzR3aRUzffKDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YpIQh/btrKGw86i6Z/RJXkwmtwHNzR3aRUzffKDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YpIQh/btrKGw86i6Z/RJXkwmtwHNzR3aRUzffKDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYpIQh%2FbtrKGw86i6Z%2FRJXkwmtwHNzR3aRUzffKDK%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;650&quot; height=&quot;339&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3c960ec7-d0b3-4501-89fb-8127248800f4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-68f3de6c-7528-4e82-9e82-09d863ebc3dd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;.gitignore 추가유무&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7f58649c-bdb0-4b42-b185-c4fe2542c20f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;339&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beljv1/btrKHwAvHgf/IHUojHpV64paF6btaMtGX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beljv1/btrKHwAvHgf/IHUojHpV64paF6btaMtGX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beljv1/btrKHwAvHgf/IHUojHpV64paF6btaMtGX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbeljv1%2FbtrKHwAvHgf%2FIHUojHpV64paF6btaMtGX0%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;650&quot; height=&quot;339&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-78ba468a-be5a-4d3a-93ff-d4f16c8ccf9d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-96a3296b-f7b4-4e90-9acb-9c43a735b913&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;의존성 모듈 설치&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8c153fa0-9877-449b-9e3d-f2691954a025&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4fcee4f4-016d-466c-8328-91e2af4c5048&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막의 의존성 모듈은 typescript 기반으로 생성했으므로 typescript 관련된 의존성을 추가합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5c0f6625-2b2d-428b-8906-a77813e2b3d8&quot;&gt;
&lt;pre id=&quot;code_1661640599694&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tree . -I node_modules
.
├── README.md
├── contracts
│   └── Greeter.sol
├── hardhat.config.ts
├── package-lock.json
├── package.json
├── scripts
│   └── deploy.ts
├── test
│   └── index.ts
└── tsconfig.json

3 directories, 8 files&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-50b7e90d-e3ee-41e1-a58d-1372a9ce8844&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-50b765a4-1984-492b-9a1b-e79b1944b5e9&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ contracts&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-0e516c6d-9882-4e3e-ab6f-518b7103086e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트 코드를 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-96b425f4-4cfb-477a-ae42-be0245c1c7c2&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ scripts(truffle에서 migrations 역할을 수행합니다.)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-e8d187fd-eb80-4fec-a428-d5d67df98ce7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트 배포를 관리합니다&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-0d8385be-1bfc-489f-9754-dab5ba35b97d&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ test&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-9458c253-a5bd-4a5d-8508-89761ebc3f46&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;테스트 코드를 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-e486fb33-46e8-4571-8574-344c1039389e&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ artifacts, cache&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-84f32ef6-2ab1-4119-b4da-afaf126ecd91&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컴파일 결과를 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-f82e809f-e9c9-4004-87e1-90bafab3ceba&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ hardhat.config.ts&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-a3141115-0c27-4fe3-9840-2f2efcae540e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;네트워크 연결정보 및 solidity compiler 버전 정보 등을 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d7408b31-6b8d-49c7-930f-2a450fcab0c6&quot;&gt;
&lt;pre id=&quot;code_1661640643439&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import * as dotenv from &quot;dotenv&quot;;

import { HardhatUserConfig, task } from &quot;hardhat/config&quot;;
import &quot;@nomiclabs/hardhat-etherscan&quot;;
import &quot;@nomiclabs/hardhat-waffle&quot;;
import &quot;@typechain/hardhat&quot;;
import &quot;hardhat-gas-reporter&quot;;
import &quot;solidity-coverage&quot;;

dotenv.config();

// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task(&quot;accounts&quot;, &quot;Prints the list of accounts&quot;, async (taskArgs, hre) =&amp;gt; {
  const accounts = await hre.ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more

const config: HardhatUserConfig = {
  solidity: &quot;0.8.4&quot;,
  networks: {
    ropsten: {
      url: process.env.ROPSTEN_URL || &quot;&quot;,
      accounts:
        process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
    },
  },
  gasReporter: {
    enabled: process.env.REPORT_GAS !== undefined,
    currency: &quot;USD&quot;,
  },
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY,
  },
};

export default config;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-262b610d-8c9b-4926-b640-d6196677e0bf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8259c646-db1e-4c3e-8e0b-a62f4f26e553&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;process.env는 환경변수를 가져옵니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7225a12c-657e-4e9d-b0db-85e4c69208d2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-42582cfb-6b97-429f-bafb-38882518f6a8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;hardhat은 프로젝트 생성시 .env를 생성합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-23ba51f8-0d96-4aca-b521-b44e5dcf4d7c&quot;&gt;
&lt;pre id=&quot;code_1661640652102&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1
ROPSTEN_URL=https://eth-ropsten.alchemyapi.io/v2/&amp;lt;YOUR ALCHEMY KEY&amp;gt;
PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fbd9824e-85d2-4b08-8ce8-402c3cd347b1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-653bfae4-e585-4ef4-9b16-27ba4f67d5a5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;hardhat은 etherscan과 연동되어 특정 액션을 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-4d2d6ed0-7c73-487f-856d-65fc511ddc01&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 의존성 모듈 확인하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-aecb6350-ba13-40f6-a177-a86ca4797711&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;package.json을 확인하면 앞의 명령어로 생성한 프로젝트가 얼마나 많은 라이브러리와 의존성을 가지는지 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e8263c5e-c2c8-4a5d-98e4-1e3f47c63ba8&quot;&gt;
&lt;pre id=&quot;code_1661640664815&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;hardhat-project&quot;,
  &quot;devDependencies&quot;: {
    &quot;@nomiclabs/hardhat-ethers&quot;: &quot;^2.0.3&quot;,
    &quot;@nomiclabs/hardhat-etherscan&quot;: &quot;^2.1.8&quot;,
    &quot;@nomiclabs/hardhat-waffle&quot;: &quot;^2.0.1&quot;,
    &quot;@typechain/ethers-v5&quot;: &quot;^7.2.0&quot;,
    &quot;@typechain/hardhat&quot;: &quot;^2.3.1&quot;,
    &quot;@types/chai&quot;: &quot;^4.3.0&quot;,
    &quot;@types/mocha&quot;: &quot;^9.0.0&quot;,
    &quot;@types/node&quot;: &quot;^12.20.37&quot;,
    &quot;@typescript-eslint/eslint-plugin&quot;: &quot;^4.33.0&quot;,
    &quot;@typescript-eslint/parser&quot;: &quot;^4.33.0&quot;,
    &quot;chai&quot;: &quot;^4.3.4&quot;,
    &quot;dotenv&quot;: &quot;^10.0.0&quot;,
    &quot;eslint&quot;: &quot;^7.32.0&quot;,
    &quot;eslint-config-prettier&quot;: &quot;^8.3.0&quot;,
    &quot;eslint-config-standard&quot;: &quot;^16.0.3&quot;,
    &quot;eslint-plugin-import&quot;: &quot;^2.25.3&quot;,
    &quot;eslint-plugin-node&quot;: &quot;^11.1.0&quot;,
    &quot;eslint-plugin-prettier&quot;: &quot;^3.4.1&quot;,
    &quot;eslint-plugin-promise&quot;: &quot;^5.2.0&quot;,
    &quot;ethereum-waffle&quot;: &quot;^3.4.0&quot;,
    &quot;ethers&quot;: &quot;^5.5.2&quot;,
    &quot;hardhat&quot;: &quot;^2.7.1&quot;,
    &quot;hardhat-gas-reporter&quot;: &quot;^1.0.6&quot;,
    &quot;prettier&quot;: &quot;^2.5.1&quot;,
    &quot;prettier-plugin-solidity&quot;: &quot;^1.0.0-beta.13&quot;,
    &quot;solhint&quot;: &quot;^3.3.6&quot;,
    &quot;solidity-coverage&quot;: &quot;^0.7.17&quot;,
    &quot;ts-node&quot;: &quot;^10.4.0&quot;,
    &quot;typechain&quot;: &quot;^5.2.0&quot;,
    &quot;typescript&quot;: &quot;^4.5.4&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-569b2793-54e6-4566-bb47-66e6bfb410fb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;SE-9f50209e-8a4e-40bc-984f-7f38d1a5c8bd&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 개발 프로세스&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-8c033ca8-a0bd-4ed7-92a0-b0ca466708c9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;일반적으로 개발이라하면 다음과 같은 프로세스에 맞춰서 개발합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dab9bb56-da37-41d4-856d-56494900ec1b&quot;&gt;
&lt;pre id=&quot;code_1661640680633&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 소스코드 작성 
2. 컴파일 &amp;amp; 빌드 
3. 배포 
4. 개별적으로 실행해보기 
5. 테스트 하기&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-55e795a6-abe6-4d75-a24e-f0eccfc2de3e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e85f165d-a743-42ec-99ab-6cd72e868b19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;hardhat도 truffle과 마찬가지로 이런 일련의 과정을 코드 및 명령어 기반으로 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-30bb03a6-1ef8-4510-b766-3f021086c761&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 소스코드 작성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-80abe7de-69d0-491e-8793-f7e2a9a36302&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;소스 코드는 contracts 아래에서 관리합니다. 우리는 별도의 소스코드를 작성하지 않고 샘플로 제공하는 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;b&gt;Greeter.sol&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;을 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f7c3cf8-6ef4-4509-b047-1583f2b70c95&quot;&gt;
&lt;pre id=&quot;code_1661640692608&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import &quot;hardhat/console.sol&quot;;

contract Greeter {
    string private greeting;

    constructor(string memory _greeting) {
        console.log(&quot;Deploying a Greeter with greeting:&quot;, _greeting);
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        console.log(&quot;Changing greeting from '%s' to '%s'&quot;, greeting, _greeting);
        greeting = _greeting;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-27eb0dc1-846e-4911-a48d-443c2235d43b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-97da98a7-bb73-4d61-bbf7-6d792ec7ac21&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;여기서 한 가지 중요한 점은 console.log를 사용한다는 점입니다. hardhat팀은 스마트 컨트랙트 개발시 마치 자바스크립트처럼 디버깅할 수 있도록 도와주는 console.log 라이브러리를 제공하고 있습니다.&lt;/span&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-60063766-ebdd-428d-a742-d1f744e2d6cf&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 컴파일&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b3d27d8f-6c66-4d1d-9b66-13991d843ff3&quot;&gt;
&lt;pre id=&quot;code_1661640710467&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx hardhat compile

Downloading compiler 0.8.4
Compiling 2 files with 0.8.4
Generating typings for: 2 artifacts in dir: typechain for target: ethers-v5
Successfully generated 5 typings!
Compilation finished successfully&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-90e95f0b-3f8f-4232-b021-31f20a91b2d3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3a1c12b2-f338-478a-ba45-d2453429e8cb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;컴파일을 완료하면 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;b&gt;artifacts&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;b&gt;cache&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt; 디렉터리를 생성합니다. 만약, 컨트랙트 코드에 문제가 있다면 문제에 대한 메시지를 출력합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8586d1c2-d583-482b-8622-1116b6012960&quot;&gt;
&lt;pre id=&quot;code_1661640717751&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tree  -I node_modules           
.
├── README.md
├── artifacts
│   ├── build-info
│   │   └── f6d72e584f9c6e176d0b340e8f9097a9.json
│   ├── contracts
│   │   └── Greeter.sol
│   │       ├── Greeter.dbg.json
│   │       └── Greeter.json
│   └── hardhat
│       └── console.sol
│           ├── console.dbg.json
│           └── console.json
├── cache
│   └── solidity-files-cache.json
├── contracts
│   └── Greeter.sol
├── hardhat.config.ts
├── package-lock.json
├── package.json
├── scripts
│   └── deploy.ts
├── test
│   └── index.ts
├── tsconfig.json
└── typechain
    ├── Greeter.d.ts
    ├── common.d.ts
    ├── factories
    │   └── Greeter__factory.ts
    ├── hardhat.d.ts
    └── index.ts

12 directories, 19 files&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-24cd76de-e69d-438b-8f56-016846ff24a9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-11a7a909-f0c2-4764-ade7-f6b4e8a3d03b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;우리가 dapp을 만들 때 필요한 요소중 하나인 ABI와 bytecode는 artifacts/contracts 아래의 우리가 작성한 solidity 파일명인 Greeter.sol 아래에서 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-026cff79-57c6-43d3-9790-c5906c8d1b23&quot;&gt;
&lt;pre id=&quot;code_1661640727712&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;_format&quot;: &quot;hh-sol-artifact-1&quot;,
  &quot;contractName&quot;: &quot;Greeter&quot;,
  &quot;sourceName&quot;: &quot;contracts/Greeter.sol&quot;,
  &quot;abi&quot;: [
    {
      &quot;inputs&quot;: [
        {
          &quot;internalType&quot;: &quot;string&quot;,
          &quot;name&quot;: &quot;_greeting&quot;,
          &quot;type&quot;: &quot;string&quot;
        }
      ],
      &quot;stateMutability&quot;: &quot;nonpayable&quot;,
      &quot;type&quot;: &quot;constructor&quot;
    },
    {
      &quot;inputs&quot;: [],
      &quot;name&quot;: &quot;greet&quot;,
      &quot;outputs&quot;: [
        {
          &quot;internalType&quot;: &quot;string&quot;,
          &quot;name&quot;: &quot;&quot;,
          &quot;type&quot;: &quot;string&quot;
        }
      ],
      &quot;stateMutability&quot;: &quot;view&quot;,
      &quot;type&quot;: &quot;function&quot;
    },
    {
      &quot;inputs&quot;: [
        {
          &quot;internalType&quot;: &quot;string&quot;,
          &quot;name&quot;: &quot;_greeting&quot;,
          &quot;type&quot;: &quot;string&quot;
        }
      ],
      &quot;name&quot;: &quot;setGreeting&quot;,
      &quot;outputs&quot;: [],
      &quot;stateMutability&quot;: &quot;nonpayable&quot;,
      &quot;type&quot;: &quot;function&quot;
    }
  ],
  &quot;bytecode&quot;: &quot;생략&quot;,
  &quot;deployedByBytecode&quot;:  &quot;생략&quot;,
  &quot;linkReferences&quot;: {},
  &quot;deployedLinkReferences&quot;: {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1698be63-a364-4f71-aaab-af17837b2a3d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-98a59edb-75fa-4758-9763-dd60f1402da2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt; truffle의 컴파일 결과보다 필요한 정보만 가지고 있어서 이 부분은 hardhat이 맘에 드는 요소중 하나입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ee4bfb94-7376-46e3-a889-262044c005f0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;또한 해당 프로젝트를 typescript 기반으로 생성했기 때문에 typechain 디렉터리도 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c2994886-828e-4667-bf4c-13349ee8e600&quot;&gt;
&lt;pre id=&quot;code_1661640736320&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.
├── Greeter.d.ts
├── common.d.ts
├── factories
│   └── Greeter__factory.ts
├── hardhat.d.ts
└── index.ts

1 directory, 5 files&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-30a0ae68-f622-4d4d-bcee-bf5e1e9dd4e9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1a4aa5d6-b216-4410-8ab6-2cfd87b12f36&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;해당 파일은 contracts 파일에 대한 인터페이스 정의입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fdd4b17a-f178-459c-8219-9b4811e49ab8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-48bb3a42-b206-4b88-b90d-3db33f03cc06&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 테스트&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-7fe6adfb-eb9e-4a01-9cad-7d8b87632bcb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;테스트 코드는 test에서 관리합니다. 이 부분도 샘플로 제공하는 코드를 기준으로 진행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7dade08b-4fc9-4c33-97d5-f499393dbabf&quot;&gt;
&lt;pre id=&quot;code_1661640753153&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { expect } from &quot;chai&quot;;
import { ethers } from &quot;hardhat&quot;;

describe(&quot;Greeter&quot;, function () {
  it(&quot;Should return the new greeting once it's changed&quot;, async function () {
    const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);
    const greeter = await Greeter.deploy(&quot;Hello, world!&quot;);
    await greeter.deployed();

    expect(await greeter.greet()).to.equal(&quot;Hello, world!&quot;);

    const setGreetingTx = await greeter.setGreeting(&quot;Hola, mundo!&quot;);

    // wait until the transaction is mined
    await setGreetingTx.wait();

    expect(await greeter.greet()).to.equal(&quot;Hola, mundo!&quot;);
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-466af2fb-b4b4-4e30-a77f-0e53ad7b9b51&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8b688060-821d-4fa4-aaf8-cd68a0997fe1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;해당 코드의 흐름은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-b6bbec39-95ed-423b-b328-839cb27af115&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 1. 컨트랙트 팩토리 메서드를 이용하여 Greeter 배포객체 가져오기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8cde2677-fe36-4d1d-b1a4-b64ac178cf8f&quot;&gt;
&lt;pre id=&quot;code_1661640810259&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-61b9e2e4-5407-4d80-a314-9c395a1374d5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-278ce00b-e6ee-46c5-967d-086034ca2df5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;여기서 팩토리란 factory를 의미합니다. 프로그래밍에서 팩토리란 객체를 만드는 함수를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-b28de934-712d-4597-86e0-6136e01faa08&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 2. 팩토리를 통해 가져온 컨트랙트 정보를 토대로 Hello world!를 초기값으로 가지는 컨트랙트 배포준비&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0a268d63-dec0-4e17-a295-8073b687c3ea&quot;&gt;
&lt;pre id=&quot;code_1661640815291&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const greeter = await Greeter.deploy(&quot;Hello, world!&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e7c5d14c-8f68-48e7-ac4d-819fa06c968b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-7a1234f3-0367-40ec-82f4-d30328e32ad4&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 3. 컨트랙트 배포&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ad28d6a6-4aeb-4e5c-afa2-843ad5c7e3db&quot;&gt;
&lt;pre id=&quot;code_1661640819771&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;await greeter.deployed();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ee06d911-569c-4b05-a9cb-03c72957c6cf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-01202edb-31ce-481b-b7ec-60b246a6669b&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 4. 생성자에 의한 초기값 기대값 확인&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e1ab12df-2b8f-4002-8a1d-c5b5998df491&quot;&gt;
&lt;pre id=&quot;code_1661640826356&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;expect(await greeter.greet()).to.equal(&quot;Hello, world!&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0a90dc31-573e-4ae6-a8b6-a7da548baecf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-91dbb99f-0836-4895-ae56-c5cd91e9a4a2&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 5. setGreeting() 호출하여 Hello, world!를 Hola, mundo!로 변경 - 트랜잭션 발생&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-73ccf2d1-2a8d-43e5-803b-013c797c0aa6&quot;&gt;
&lt;pre id=&quot;code_1661640833932&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const setGreetingTx = await greeter.setGreeting(&quot;Hola, mundo!&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f503be9d-9488-414d-9f99-f549a580c0be&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-39c0ca9e-4040-4235-b0cf-8c97dd26bb61&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 6.트랜잭션이 블록에 포함할 때까지 기다림&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-83bcfd01-b740-43ce-a0a8-b0e658e2594e&quot;&gt;
&lt;pre id=&quot;code_1661640841267&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;await setGreetingTx.wait();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6d76d2a6-e141-440b-bc12-b9384a1afe47&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-bc0e22cc-6036-44bf-a456-af83d98e91e3&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 7. 6번으로 변경한 기대값 확인&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4b83b345-a696-4641-8b63-d5fdae373a9c&quot;&gt;
&lt;pre id=&quot;code_1661640846461&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;expect(await greeter.greet()).to.equal(&quot;Hola, mundo!&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1661640878124&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx hardhat test

No need to generate any newer typings.

  Greeter
Deploying a Greeter with greeting: Hello, world!
Changing greeting from 'Hello, world!' to 'Hola, mundo!'
    ✓ Should return the new greeting once it's changed (601ms)

  1 passing (606ms)&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-25d1c091-c550-4b98-8a2d-bc1b9995ec5b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1ebec079-df4c-424f-adee-cc15b7aa05f7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ezCvON/btrKJ4XvAug/CNVpsFXcy3J3txkkTb5KR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ezCvON/btrKJ4XvAug/CNVpsFXcy3J3txkkTb5KR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ezCvON/btrKJ4XvAug/CNVpsFXcy3J3txkkTb5KR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FezCvON%2FbtrKJ4XvAug%2FCNVpsFXcy3J3txkkTb5KR1%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;690&quot; height=&quot;267&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9e4586aa-b3a1-42ca-bb07-cd79e3184d07&quot;&gt;
&lt;pre id=&quot;code_1661640885709&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; $ npx hardhat test test/index.ts&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-518fcdaf-b621-4306-baca-ec2105720ee3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6c93fe09-1e31-4e02-b221-b8e61cdf0f64&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;특정 파일을 명시하면 특정 파일만 테스트 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-713814d1-4e5e-4f2b-9ed7-e2f6f556bdf0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 배포 &lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-3427aafb-f96a-42e3-a3f1-cadb28ace46e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;배포는 scripts에서 관리하며 run 명령어를 이용합니다. 이 또한 샘플로 제공한 deploy.ts 파일을 이용합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c292927c-2593-4b10-80e6-0d2abb6eeae8&quot;&gt;
&lt;pre id=&quot;code_1661640904680&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ethers } from &quot;hardhat&quot;;

async function main() {
  const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);
  const greeter = await Greeter.deploy(&quot;Hello, Hardhat!&quot;);

  await greeter.deployed();

  console.log(&quot;Greeter deployed to:&quot;, greeter.address);
}

main().catch((error) =&amp;gt; {
  console.error(error);
  process.exitCode = 1;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7115b8ce-a06a-49f8-9ad7-516ebcb595db&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1ae861c3-f921-4ecf-acea-cb188586d54d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;앞의 테스트 코드에서 다뤄본 내용입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c08edd65-49b9-4e78-9025-b677fe93df54&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eaadd0e5-22dc-427e-9e78-79688feb02b4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;한 가지 이상하다고 느낄 수 있는 부분은 다음 부분일겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a3e0cae3-3da0-426e-a951-8d4f9ad7d1fb&quot;&gt;
&lt;pre id=&quot;code_1661640910605&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;main().catch((error) =&amp;gt; {
  console.error(error);
  process.exitCode = 1;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-441ccf32-42fd-47ed-8c27-1bfaad103075&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b9670cae-3222-4f0a-bbc4-6ce1ebd6fb5c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;이건 main() 함수의 반환 타입이 Promise 이기 때문에 then() 또는 catch()로 체이닝이 가능합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-36a4af38-44cd-4375-b820-172fee2c92ff&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f361618f-0c7c-4bfb-8692-d9adf8bc2a46&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d1da54a0-4e04-4778-be79-5eb4739d3b0a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;배포하기 전에 해야할 작업이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bc1f3596-0407-404f-8224-d792db84fb47&quot;&gt;
&lt;pre id=&quot;code_1661640928847&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 네트워크 환경 구성
2. hardhat 배포 네트워크 설정&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5e2b5f25-881f-4b3c-810c-13d8ecb2a58c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-24166291-d8ac-4ca4-bc4d-5aefcfaef896&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;여기선 ganache-cli로 구축한 네트워크에 배포를 진행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-649725c7-647e-4996-b05c-a052dcc99bc6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-8b8aa0f9-d41c-4115-998f-0b55d65fada4&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 로컬 네트워크 구축&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-531a92c7-2497-479c-b395-d494d940b35f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;아마 제 블로그를 꾸준히 보신분은 ganache-cli을 어떻게 실행하는지 아실겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-93c0ab0d-549d-4d43-951d-9cb27e738eb7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-918e373a-f6ad-4571-b249-c8f23651517a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;하지만 전 너무나 친절한 멍개이기 때문에 설치방법과 실행방법을 알려드립니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0009992a-c56a-4ffd-8b5c-5df0e030af6f&quot;&gt;
&lt;pre id=&quot;code_1661640945111&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install -g ganache-cli # 설치

$ ganache-cli # 실행
Ganache CLI v6.12.2 (ganache-core: 2.13.2)

Available Accounts
==================
(0) 0x6b113534c1ef028e2F90d2338F491E49EB70879c (100 ETH)
(1) 0x9BEae85001A0c3F09688345145498919423b5E8C (100 ETH)
(2) 0xF7718Dd4e188C160A051834D6F37399D64b96F5A (100 ETH)
(3) 0x9d56FFe5bF0DeAF33c70883681B09ecD0F010ac4 (100 ETH)
(4) 0x7A61860f47Bc42A865d9424d8eDC70705602300e (100 ETH)
(5) 0xd673AFCD67FFD1dedc9FbAE4cEf0A08Eb0aCD13A (100 ETH)
(6) 0xab90Abfe30dcfcf0318D4985C9d3518D24b14475 (100 ETH)
(7) 0x54E2F2BBEdb351d4eD12F34B1Df83e5fc061df1C (100 ETH)
(8) 0xB70454565eA14AB414C80a540A1022Af43597628 (100 ETH)
(9) 0xD43B9c31624a17731336516b75177cCB40358741 (100 ETH)

Private Keys
==================
(0) 0x78cc9813aa135f44dcba76b1a751271591640473cf039a0efb60d27491dab144
(1) 0x84fa91cc7df9476856ae603edc3e84e3b57782f9eea37c6e2400a0c4124f8005
(2) 0xa4da287dc643a1f5732137fc5900ffe2edf09a37b3c5d281f3610a2b2c7019a1
(3) 0xc04aac3b8bf75548e52bd437546524649da52dc9ec0897041fa3f07630ad87d0
(4) 0x0608b4d7bc929e4a4f444764ca904b1942df2b198f7604f88e57697e5e76baa7
(5) 0xbfc2e7155d0b287081992e0b41bda7560e901920d8f72cd39446364bd9ed0bcf
(6) 0xfbf0fef2691d3b822daf11e2190fa506cd4eba929dcc904af39eb54b30bff59e
(7) 0x5381c52fe5a80b2bdfc831bb129ed211b131c4ec4f488756f62c64704b082ca0
(8) 0xe317b2db45f3c334c969345c25032a9ef50b04b42f87b8c53e255cd7cba01d7f
(9) 0xfe3ad5e53cfca3d36bbd11984c25f5db8a118252735ad59370f13322271f0011

HD Wallet
==================
Mnemonic:      world globe scale buddy peace position broccoli autumn move local saddle snow
Base HD Path:  m/44'/60'/0'/0/{account_index}

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Call Gas Limit
==================
9007199254740991

Listening on 127.0.0.1:8545&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-19cd9caa-3793-45a4-87be-f3e5b41a865f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ff1f36a7-71a8-44ab-8902-ca717b6f20c4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;만약, ganache-cli가 지겨우신 가요? 그렇다면 hardhat이 제공하는 노드를 이용해도 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9895f390-a275-455d-b6a6-bd691e23b939&quot;&gt;
&lt;pre id=&quot;code_1661640964744&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/

Accounts
========

WARNING: These accounts, and their private keys, are publicly known.
Any funds sent to them on Mainnet or any other live network WILL BE LOST.

Account #0: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266 (10000 ETH)
Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

Account #1: 0x70997970c51812dc3a010c7d01b50e0d17dc79c8 (10000 ETH)
Private Key: 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d

Account #2: 0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc (10000 ETH)
Private Key: 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a

Account #3: 0x90f79bf6eb2c4f870365e785982e1f101e93b906 (10000 ETH)
Private Key: 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6

Account #4: 0x15d34aaf54267db7d7c367839aaf71a00a2c6a65 (10000 ETH)
Private Key: 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a

Account #5: 0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc (10000 ETH)
Private Key: 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba

Account #6: 0x976ea74026e726554db657fa54763abd0c3a0aa9 (10000 ETH)
Private Key: 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e

Account #7: 0x14dc79964da2c08b23698b3d3cc7ca32193d9955 (10000 ETH)
Private Key: 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356

Account #8: 0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f (10000 ETH)
Private Key: 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97

Account #9: 0xa0ee7a142d267c1f36714e4a8f75612f20a79720 (10000 ETH)
Private Key: 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6

Account #10: 0xbcd4042de499d14e55001ccbb24a551f3b954096 (10000 ETH)
Private Key: 0xf214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897

Account #11: 0x71be63f3384f5fb98995898a86b02fb2426c5788 (10000 ETH)
Private Key: 0x701b615bbdfb9de65240bc28bd21bbc0d996645a3dd57e7b12bc2bdf6f192c82

Account #12: 0xfabb0ac9d68b0b445fb7357272ff202c5651694a (10000 ETH)
Private Key: 0xa267530f49f8280200edf313ee7af6b827f2a8bce2897751d06a843f644967b1

Account #13: 0x1cbd3b2770909d4e10f157cabc84c7264073c9ec (10000 ETH)
Private Key: 0x47c99abed3324a2707c28affff1267e45918ec8c3f20b8aa892e8b065d2942dd

Account #14: 0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097 (10000 ETH)
Private Key: 0xc526ee95bf44d8fc405a158bb884d9d1238d99f0612e9f33d006bb0789009aaa

Account #15: 0xcd3b766ccdd6ae721141f452c550ca635964ce71 (10000 ETH)
Private Key: 0x8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61

Account #16: 0x2546bcd3c84621e976d8185a91a922ae77ecec30 (10000 ETH)
Private Key: 0xea6c44ac03bff858b476bba40716402b03e41b8e97e276d1baec7c37d42484a0

Account #17: 0xbda5747bfd65f08deb54cb465eb87d40e51b197e (10000 ETH)
Private Key: 0x689af8efa8c651a91ad287602527f3af2fe9f6501a7ac4b061667b5a93e037fd

Account #18: 0xdd2fd4581271e230360230f9337d5c0430bf44c0 (10000 ETH)
Private Key: 0xde9be858da4a475276426320d5e9262ecfc3ba460bfac56360bfa6c4c28b4ee0

Account #19: 0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199 (10000 ETH)
Private Key: 0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e

WARNING: These accounts, and their private keys, are publicly known.
Any funds sent to them on Mainnet or any other live network WILL BE LOST.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d44c5696-862d-4d42-97db-4e5b361e69eb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b423a2f2-1a87-436f-b9ac-f80de0e4b9f1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;여기서는 ganache-cli로 진행합니다. 사실 머로 진행하든 상관없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-db8c57d3-da80-43f2-bc96-055f75002291&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ hardhat.config.ts&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p id=&quot;SE-4a452851-28d6-4fe7-b8cd-031cb1477e15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;hardhat에서 배포할 네트워크를 수정할 차례입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1da7fb0c-8daa-46ee-97d2-2c842f841920&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6cb17c62-fd40-4df9-8cda-78ffd6696af5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661640983241&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import * as dotenv from &quot;dotenv&quot;;

import { HardhatUserConfig, task } from &quot;hardhat/config&quot;;
import &quot;@nomiclabs/hardhat-etherscan&quot;;
import &quot;@nomiclabs/hardhat-waffle&quot;;
import &quot;@typechain/hardhat&quot;;
import &quot;hardhat-gas-reporter&quot;;
import &quot;solidity-coverage&quot;;

dotenv.config();

task(&quot;accounts&quot;, &quot;Prints the list of accounts&quot;, async (taskArgs, hre) =&amp;gt; {
  const accounts = await hre.ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more

const config: HardhatUserConfig = {
  solidity: &quot;0.8.4&quot;,
  networks: {
    ropsten: {
      url: process.env.ROPSTEN_URL || &quot;&quot;,
      accounts:
        process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
    },
    dev: {
      url: &quot;http://localhost:8545&quot;,
      accounts: [
        &quot;0x78cc9813aa135f44dcba76b1a751271591640473cf039a0efb60d27491dab144&quot;,
        &quot;0x84fa91cc7df9476856ae603edc3e84e3b57782f9eea37c6e2400a0c4124f8005&quot;,
        &quot;0xa4da287dc643a1f5732137fc5900ffe2edf09a37b3c5d281f3610a2b2c7019a1&quot;,
        &quot;0xc04aac3b8bf75548e52bd437546524649da52dc9ec0897041fa3f07630ad87d0&quot;,
        &quot;0x0608b4d7bc929e4a4f444764ca904b1942df2b198f7604f88e57697e5e76baa7&quot;,
        &quot;0xbfc2e7155d0b287081992e0b41bda7560e901920d8f72cd39446364bd9ed0bcf&quot;,
        &quot;0xfbf0fef2691d3b822daf11e2190fa506cd4eba929dcc904af39eb54b30bff59e&quot;,
        &quot;0x5381c52fe5a80b2bdfc831bb129ed211b131c4ec4f488756f62c64704b082ca0&quot;,
        &quot;0xe317b2db45f3c334c969345c25032a9ef50b04b42f87b8c53e255cd7cba01d7f&quot;,
        &quot;0xfe3ad5e53cfca3d36bbd11984c25f5db8a118252735ad59370f13322271f0011&quot;,
      ],
    },
  },
  gasReporter: {
    enabled: process.env.REPORT_GAS !== undefined,
    currency: &quot;USD&quot;,
  },
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY,
  },
};

export default config;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-9b459acb-1bdd-4caa-830b-bc5376aef35e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;network에 truffle.config.js와 비슷한 형태로 추가합니다. 이때 중요한 점은 accounts를 넣어줘야 합니다. accounts는 개인키(privatekey)를 넣어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bb1d2c91-cc08-4c10-abce-52524f5578e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-d3790965-dd1d-466e-ad06-af5c245f0436&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 배포&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c2ca3573-6233-4a0c-ad17-887ccc3653c6&quot;&gt;
&lt;pre id=&quot;code_1661641001681&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx hardhat run --network dev scripts/deploy.ts

No need to generate any newer typings.
Greeter deployed to: 0x2977ae3f2C5473d6cebcfE37be94BA59ce1Dd483&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4a5436ab-0b32-446d-bcbc-ab7e7b7e59e8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f3834e3d-c60b-46c0-a768-d82d6d28783a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;deploy.ts 파일 main() 함수의 마지막의 다음과 같이 콘솔이 있어 마지막에 배포한 컨트랙트 주소를 출력합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-12ebf1c5-bfcb-4030-bd1b-5d6c42e289d9&quot;&gt;
&lt;pre id=&quot;code_1661641008993&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(&quot;Greeter deployed to:&quot;, greeter.address);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6767ed15-63fc-4221-bf5f-2c06e8b79b33&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f26beb8b-0ee7-49d0-ae70-d7b4fafe2338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;만약 배포시 hardhat.config.ts의 network에 명시한 accounts를 가져오고 싶다면 다음과 같이 가져올 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-df316e6c-b9cb-4383-8107-78a12f327ca8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661641015425&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ethers } from &quot;hardhat&quot;;

const accounts = await ethers.getSigners();

for (const account of accounts) {
    console.log(account.address);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-29481943-6faf-4cd6-92c8-dbb924eabbd5&quot;&gt;
&lt;pre id=&quot;code_1661641021619&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ethers } from &quot;hardhat&quot;;

async function main() {
  const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);
  const greeter = await Greeter.deploy(&quot;Hello, Hardhat!&quot;);
  const accounts = await ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }

  await greeter.deployed();
  console.log(&quot;Greeter deployed to:&quot;, greeter.address);
}

main().catch((error) =&amp;gt; {
  console.error(error);
  process.exitCode = 1;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5dd27446-68ed-4190-a743-7a7e8ca027f3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7754033f-85aa-4254-9c0e-8d1c8e2778a1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;다시 배포합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d7d0a5e0-a07e-4992-ac9e-ca52e7f013ed&quot;&gt;
&lt;pre id=&quot;code_1661641030728&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx hardhat run --network dev scripts/deploy.ts 

No need to generate any newer typings.
0x6b113534c1ef028e2F90d2338F491E49EB70879c
0x9BEae85001A0c3F09688345145498919423b5E8C
0xF7718Dd4e188C160A051834D6F37399D64b96F5A
0x9d56FFe5bF0DeAF33c70883681B09ecD0F010ac4
0x7A61860f47Bc42A865d9424d8eDC70705602300e
0xd673AFCD67FFD1dedc9FbAE4cEf0A08Eb0aCD13A
0xab90Abfe30dcfcf0318D4985C9d3518D24b14475
0x54E2F2BBEdb351d4eD12F34B1Df83e5fc061df1C
0xB70454565eA14AB414C80a540A1022Af43597628
0xD43B9c31624a17731336516b75177cCB40358741
Greeter deployed to: 0x825f751DAd1Cf797DF67d604c604A58e9B49c4b0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4bc0ee3a-a2dc-4bee-be08-d290654aba6b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-6f8be378-99ad-43ae-931d-11f574d83dbc&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 콘솔모드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a276f36e-4990-4925-b467-8d1271f0a9bc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;hardhat도 truffle처럼 콘솔모드를 지원합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6e8fb4a9-a270-425d-8540-5008734666cc&quot;&gt;
&lt;pre id=&quot;code_1661641043066&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npx hardhat console --network dev
No need to generate any newer typings.
Welcome to Node.js v14.17.3.
Type &quot;.help&quot; for more information.
&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9e3993b5-b50e-4159-bc36-162495412e8e&quot;&gt;
&lt;pre id=&quot;code_1661641048635&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; const { ethers } = require('hardhat');
undefined

&amp;gt; (await ethers.getSigners()).slice(0, 2).map(item =&amp;gt; item.address)
[
  '0x6b113534c1ef028e2F90d2338F491E49EB70879c',
  '0x9BEae85001A0c3F09688345145498919423b5E8C'
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-44a942b9-e80f-436d-b163-c73b2eb76710&quot;&gt;
&lt;pre id=&quot;code_1661641056658&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; const Greeter = await ethers.getContractFactory(&quot;Greeter&quot;);
undefined
&amp;gt; const greeter = await Greeter.deploy(&quot;Hello, Hardhat!&quot;);
undefined
&amp;gt; const accounts = await ethers.getSigners();

&amp;gt; for (const account of accounts.slice(0, 2)) {
    console.log(account.address);
  }

0x6b113534c1ef028e2F90d2338F491E49EB70879c
0x9BEae85001A0c3F09688345145498919423b5E8C&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e38fdd28-063e-4deb-9d4c-272902f30a12&quot;&gt;
&lt;pre id=&quot;code_1661641063546&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; await greeter.deployed();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5dba8453-3d75-4ffa-bbe4-90271ab0f26b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a84121c0-6bd5-47fb-a2ab-038b82add296&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;deployed()를 수행하면 먼가 쏼롸쏼라 많이 출력 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1658238a-ab08-4682-af8b-7a4351e543fd&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06412d28-aae0-4133-8f1c-f1536e96f646&quot;&gt;
&lt;pre id=&quot;code_1661641069666&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; console.log(&quot;Greeter deployed to:&quot;, greeter.address);
Greeter deployed to: 0x391947d818B5b4E9E9bD79600B51468771172F18&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c3ca6423-fa3c-4e9d-82ff-d38c0c2749d8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1b4d7f22-b8f0-4ada-a226-af6ed5485c73&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9b113265-479c-4926-80a8-32b2902c3afb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;지금까지 hardhat을 이용하여 개발 - 컴파일 - 테스트 - 배포 과정을 알아보았습니다. 또한 scripts의 과정을 콘솔모드에서 직접 수행해보았습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c34ba471-0f2e-43fb-8070-f048386b1786&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0e84d756-99f4-47dc-96f9-aee9281558c6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;hardhat은 상당히 많은 기능을 제공합니다 .&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-86170c79-51eb-4e39-a24f-cea014abc734&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-31c067e4-f6a3-44a1-b899-57bb0711f243&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;저도 truffle에서 hardhat으로 넘어갈 생각입니다. 저도 써보면서 쓸만한 기능은 정리해서 공유하겠습니다&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ebb04e2f-428f-47e0-ad72-94007f44366e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fb8ece90-7a97-4946-b133-bb8fa8b7a412&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;a href=&quot;https://hardhat.org/&quot;&gt;https://hardhat.org/&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661641077581&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Hardhat | Ethereum development environment for professionals by Nomic Foundation&quot; data-og-description=&quot;Hardhat is an Ethereum development environment. Compile your contracts and run them on a development network. Get Solidity stack traces, console.log and more.&quot; data-og-host=&quot;hardhat.org&quot; data-og-source-url=&quot;https://hardhat.org/&quot; data-og-url=&quot;https://hardhat.org&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/W4Xxm/hyPAzMcR6z/6DkESDoG3At0MKjoey6Dmk/img.jpg?width=1024&amp;amp;height=533&amp;amp;face=0_0_1024_533&quot;&gt;&lt;a href=&quot;https://hardhat.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hardhat.org/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/W4Xxm/hyPAzMcR6z/6DkESDoG3At0MKjoey6Dmk/img.jpg?width=1024&amp;amp;height=533&amp;amp;face=0_0_1024_533');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Hardhat | Ethereum development environment for professionals by Nomic Foundation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hardhat is an Ethereum development environment. Compile your contracts and run them on a development network. Get Solidity stack traces, console.log and more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hardhat.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>Ethereum</category>
      <category>hardhat</category>
      <category>solidity</category>
      <category>truffle</category>
      <category>솔리디티</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/83</guid>
      <comments>https://meongae.tistory.com/83#entry83comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:58:09 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] solidity withdrawals pattern(출금패턴)</title>
      <link>https://meongae.tistory.com/82</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt; solidity에서 출금패턴을 다뤄보겠습니다.&lt;/span&gt;&lt;/p&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;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;제가 이 포스팅을 위해 삽질한 과정을 보고 싶다면&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=6g5Tzs9x9ec&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/s7aDI/hyPBMb5miA/gjbATewQPsRQNM8mOthCQ0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/6g5Tzs9x9ec&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;여기로 오시면 되겠습니다. 약 2시간 30분동안 삽질을 하였습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-77198180-a5eb-470a-bbd6-036a81765d6c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-0d7a9093-266c-4301-b60a-2beaa8499e16&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;☞ 목차&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2aec7a56-88d9-40c7-8522-ebc32103faf4&quot;&gt;
&lt;pre id=&quot;code_1661639585851&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 준비
2. 입/출금 가능한 스마트 컨트랙트
3. 출금패턴
4. truffle 출금 패턴 테스트 코드 작성&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-88ce6d48-49cf-4979-b94e-a1a54caa5ebf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-635810bd-5244-42bf-be4b-f61097b34059&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-dfd1f910-f6d5-41c8-bc27-754fcb2f2fc5&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 준비&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-8b6d7b34-f006-4d78-9ff1-1052d27ca6c3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크 준비, remix 네트워크 연결, metamask 네트워크 연결 및 계정준비&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a590b86e-2eb0-45dc-bae9-ef9f34727a3d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c1161068-c1a6-4ead-bf63-3c713c6be082&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 네트워크 구축&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-561f67c2-c594-41dd-bbc6-98103c6f95d9&quot;&gt;
&lt;pre id=&quot;code_1661639615053&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ganache-cli

Ganache CLI v6.12.2 (ganache-core: 2.13.2)

Available Accounts
==================
(0) 0xF3133758a5b12c99bdF762F93b86239a7Ef167f6 (100 ETH)
(1) 0x84A220f3bF83883eE93793F05506Ba512AfcBCCf (100 ETH)
(2) 0xCbf363bfbf2958725EDC0409dCd4Ea90cB94f7b6 (100 ETH)
(3) 0x7Af7683706De1F73871f7a5b5D81445E3EaE9AB2 (100 ETH)
(4) 0x9748D4c914f1b3a7B159992a0E133ad99F67EaDF (100 ETH)
(5) 0xA5a4E8d304D9D5BEc3076225d590d3bD9ccd22A2 (100 ETH)
(6) 0x14c3a4b9B0Ce420d89Ef188E1FAa536a6F4CEe25 (100 ETH)
(7) 0xC72C4B6e309b0a5A738694189523Ffa3acC86D34 (100 ETH)
(8) 0xfc6bA3aDd220Eb1B4333bbafF02C99a96c445477 (100 ETH)
(9) 0x84b5be354D9a343C0f16b98cE54E98Dcd0A57397 (100 ETH)

Private Keys
==================
(0) 0x2a137f79de5f0ade20e53bad9f7d73fa5852340df105e5b7d189f634eee6f4a9
(1) 0xfa995841f93e5dd4cdc1b61be3772d1f066b67049c3f58475aab298e66723c14
(2) 0xe38239192310bcde9c4c19a5daa7df1d0e0fa0de821083ecc511bedf5fca0536
(3) 0xec1d2c35bfbfc1c0c119af404cf60794c16d06f459a4653e9daafd94523145f7
(4) 0xc3b32dd7f90dc97bbfec3d2f552398fc94e436f0469e991747cf5f0148d2175f
(5) 0x740f283074364be311a485a5ae9e9cf5dd1ab131aba93721544cee7ee97871b9
(6) 0x162c0ac0a62f9eca99665d421497119cef6ab125022921ffc8638eab17572e67
(7) 0x2fb48a4042e9297165641a0f13f72a76dc8bda75445eb148bc09ab1035b388bd
(8) 0x3d062296e6463ac4e349526afe7ab95cdbc39ed2aca85e7ab5c61bb3784f8788
(9) 0x0fdcfc740f6095312eb2b2e1f4ff5494aca2e10559f08048e132768675177538

HD Wallet
==================
Mnemonic:      stairs another grid call actor genuine chunk hub solve picture weather settle
Base HD Path:  m/44'/60'/0'/0/{account_index}

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Call Gas Limit
==================
9007199254740991

Listening on 127.0.0.1:8545&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-742349f4-12a9-499e-93ea-3358a51fadec&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-7b33407c-5f3e-4eca-b2dc-67d29fe11113&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; remix 로컬 네트워크 연결&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-10710da8-7f0c-45e1-b2eb-0484e540228b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciP7KF/btrKMGoh3EV/lJMVcUGJFW6XZp5hgzLjA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciP7KF/btrKMGoh3EV/lJMVcUGJFW6XZp5hgzLjA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciP7KF/btrKMGoh3EV/lJMVcUGJFW6XZp5hgzLjA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciP7KF%2FbtrKMGoh3EV%2FlJMVcUGJFW6XZp5hgzLjA1%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;773&quot; height=&quot;602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-58cf3476-8ce4-4e33-b4f0-97e703dceddc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-bca907a5-4217-41da-b05d-426baa473221&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Web3 Provider 환경을 선택한 후 ganache-cli로 구축한 환경을 연결합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-46901f35-ee2a-4d2b-95ac-8a2bcd797d95&quot;&gt;
&lt;pre id=&quot;code_1661639629900&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IP: 127.0.0.1
PORT: 8545&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ce7a6951-a8d1-44a4-a7a0-c934b11fa84a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-e47bc38a-105a-48ec-a49f-8cc0400036e7&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; metamask 로컬 네트워크 연결&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6f4251e1-d5cd-4d74-a6cb-12718bc76318&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbtDTR/btrKGOBAYZV/SHYvuii2TrKGVfffEhvMo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbtDTR/btrKGOBAYZV/SHYvuii2TrKGVfffEhvMo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbtDTR/btrKGOBAYZV/SHYvuii2TrKGVfffEhvMo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbtDTR%2FbtrKGOBAYZV%2FSHYvuii2TrKGVfffEhvMo0%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;357&quot; height=&quot;600&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-60023832-da2e-49b7-b26a-6f73555710aa&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-79b3b982-8ba9-49ee-bbbf-8719a7763bf2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;metamask는 크롬 확장프로그램으로 제공하는 이더리움 지갑입니다. 지갑은 출금 패턴을 위해 스마트 컨트랙트로 이더리움을 전송해야 하는데 이더리움 전송하기 위해 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c5104819-655c-4b45-9003-704f2fbe4ec1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ganache-cli에서 제공하는 지갑을가져오고 싶다면 각각의 개인키(private key)를 개별로 가져와도 되고 니모닉(mnemonic)으로 가져와도 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-926ebe3b-3d5a-483a-b763-2cbd8d17fc5e&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7IxuV/btrKJ5B9Mwp/DajuhBMwznjCfqsoU2PN1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7IxuV/btrKJ5B9Mwp/DajuhBMwznjCfqsoU2PN1K/img.png&quot; data-alt=&quot;니모닉으로 지갑 복구하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7IxuV/btrKJ5B9Mwp/DajuhBMwznjCfqsoU2PN1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7IxuV%2FbtrKJ5B9Mwp%2FDajuhBMwznjCfqsoU2PN1K%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;357&quot; height=&quot;600&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;니모닉으로 지갑 복구하기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-499c8d59-a81d-4c9f-9dfc-300592641fe0&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o30hD/btrKGxGTPyL/w7fFnsdKU377KkzMVVVqoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o30hD/btrKGxGTPyL/w7fFnsdKU377KkzMVVVqoK/img.png&quot; data-alt=&quot;개인키로 가져오기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o30hD/btrKGxGTPyL/w7fFnsdKU377KkzMVVVqoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo30hD%2FbtrKGxGTPyL%2Fw7fFnsdKU377KkzMVVVqoK%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;357&quot; height=&quot;598&quot; data-origin-width=&quot;357&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개인키로 가져오기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-220c8e47-1626-44dc-b6dd-18c182246454&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b7508e3a-18ff-431e-9cdc-b2e2c86fac4b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-5c6b7ac5-8029-4978-837a-6929f5e57da3&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 입/출금 가능한 스마트 컨트랙트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-cba89f0c-3d6a-441a-b2a7-25db5e337a09&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출금패턴을 이해하기 위해선 스마트 컨트랙트가 이더리움을 어떤 식으로 입금/출금 하는지 이해해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-770b810e-1933-496b-8869-9a30c566d440&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 입금 가능한 스마트 컨트랙트 만들기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-4c439641-de2c-4847-8e0b-6e7504e8e7fe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;solidity는 address payable 타입을 제공합니다. address와 유사하지만 다른 타입입니다. address payable 타입은 transfer() 메서드와 balance 속성을 제공합니다. transfer() 메서드는 to.transfer()의 형태로 작성 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2e1e7f3f-c8a7-43b4-ba77-52d10aea3439&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-994df921-dd9b-4f38-b33c-8ee355754971&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;to.transfer(amount)는 해당 스마트 컨트랙트에서 to에게 amount 만큼 이더리움을 전송합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-25c5e029-1c3d-4aad-ab3d-62abe16089ca&quot;&gt;
&lt;pre id=&quot;code_1661639677509&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.10;

contract Transfer {
    constructor () {}

    function balanceOf(address payable to) external view returns(uint) {
        return to.balance;
    }

    function transfer(address payable to, uint amount) external {
        to.transfer(amount);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7bdda348-52aa-4e08-b67b-1e286857b817&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8c48c16f-943b-44c6-b2ac-91ad8752038e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 컨트랙트를 배포합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0d9e5f2c-6756-4a9a-9b56-f0c41fc885e6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FZe14/btrKGpIRs8M/ChKPyBe88KrQxpwsvXrtL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FZe14/btrKGpIRs8M/ChKPyBe88KrQxpwsvXrtL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FZe14/btrKGpIRs8M/ChKPyBe88KrQxpwsvXrtL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFZe14%2FbtrKGpIRs8M%2FChKPyBe88KrQxpwsvXrtL0%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;773&quot; height=&quot;598&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-76d4e657-2f45-43ee-8aac-3f25b59415ee&quot;&gt;
&lt;pre id=&quot;code_1661639685550&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;배포된 컨트랙트 주소(CA): 0xd1371201e390482429aF6BE4375604B790095391&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6fb47ab5-46b8-440d-a7b4-d80bdb53c704&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5f239940-61f1-4f03-898b-7ca8dd9343f1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 metamask로 해당 컨트랙트로 이더를 전송합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5ca0bc21-000c-4212-98a9-7ce7ba5a903c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-127ad35e-ad65-4062-8317-9cf91ac534fb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6CO4G/btrKJ3ddeAS/8GDXnCfoYcqmLd5dAN2cFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6CO4G/btrKJ3ddeAS/8GDXnCfoYcqmLd5dAN2cFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6CO4G/btrKJ3ddeAS/8GDXnCfoYcqmLd5dAN2cFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6CO4G%2FbtrKJ3ddeAS%2F8GDXnCfoYcqmLd5dAN2cFK%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;356&quot; height=&quot;602&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-276af80e-2e0e-4e32-be24-dc187692f2c7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1b98dcd9-b3f4-4c2e-bfce-ca135b84fb2f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1이더 전송을 시도합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ca44aa34-b42c-4f66-b24f-78102e1285a9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1cd26ef3-f1b9-4ff4-b0fa-8e5ab64520e4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C4hSH/btrKME44U4h/85zdFDNUuK7XBlguYNAFp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C4hSH/btrKME44U4h/85zdFDNUuK7XBlguYNAFp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C4hSH/btrKME44U4h/85zdFDNUuK7XBlguYNAFp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC4hSH%2FbtrKME44U4h%2F85zdFDNUuK7XBlguYNAFp1%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;338&quot; height=&quot;100&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-18c5e68e-105d-4b58-a01b-7acb886d331a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSGVan/btrKGQe8nsb/eCLUkz71VESb1XRssErheK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSGVan/btrKGQe8nsb/eCLUkz71VESb1XRssErheK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSGVan/btrKGQe8nsb/eCLUkz71VESb1XRssErheK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSGVan%2FbtrKGQe8nsb%2FeCLUkz71VESb1XRssErheK%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;354&quot; height=&quot;598&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bde4d225-8fa2-4aee-93dc-160f30eff150&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-740d96b6-847a-4e55-ba9d-8d78a91a9b80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움 전송을 실패합니다. 그 이유는 스마트 컨트랙트가 이더리움을 전송받기 위해선 특수한 함수가 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-03b90d51-29ac-40bb-8289-a53018befc7a&quot;&gt;
&lt;pre id=&quot;code_1661639700583&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.10;

contract Transfer {
    constructor () {}

    receive() external payable {}

    function balanceOf(address payable to) external view returns(uint) {
        return to.balance;
    }

    function transfer(address payable to, uint amount) external {
        to.transfer(amount);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-40e5922d-7a11-4fc5-bfa5-3e01dd8ab85e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-85f4ffcd-d158-47ce-86e9-28ee06ff73df&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;바로 &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;b&gt;receive() external payable&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 함수입니다. 해당 함수는 지갑으로 이더리움을 전송할 때 호출되는 함수입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0ffae821-16e4-493a-9601-e2df6c841cbf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCzblr/btrKGQlUG97/VlQijJQkmIMfksJVHwnQq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCzblr/btrKGQlUG97/VlQijJQkmIMfksJVHwnQq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCzblr/btrKGQlUG97/VlQijJQkmIMfksJVHwnQq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCzblr%2FbtrKGQlUG97%2FVlQijJQkmIMfksJVHwnQq1%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;773&quot; height=&quot;631&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-826a633f-6b1b-4a23-9cd2-e1c1f6c39d4f&quot;&gt;
&lt;pre id=&quot;code_1661639709398&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;배포된 컨트랙트 주소(CA): 0x4d3063CD0e79DDF4d636b344802126F06CB0f41b&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5ee0a92d-02b9-4972-a0e4-1d67c2b42158&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fe330dab-f33e-4ea3-80b9-09d0ca285bb8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마찬가지로 metamask를 통해 해당 컨트랙트로 이더리움을 전송할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-487deb0a-7e2b-4920-b8d8-e047ebe69042&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5ea22d5b-9644-4053-a1f2-2bcc3e627161&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C6LEL/btrKLhoK7Wb/BktkPFLCgPRkbCZBI4CeAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C6LEL/btrKLhoK7Wb/BktkPFLCgPRkbCZBI4CeAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C6LEL/btrKLhoK7Wb/BktkPFLCgPRkbCZBI4CeAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC6LEL%2FbtrKLhoK7Wb%2FBktkPFLCgPRkbCZBI4CeAK%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;355&quot; height=&quot;598&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6decce40-0141-4c6b-9cc7-a76a04ed549c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOz7yC/btrKHcvvLsi/FB2mgKcMQk0vvLLMoTFzSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOz7yC/btrKHcvvLsi/FB2mgKcMQk0vvLLMoTFzSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOz7yC/btrKHcvvLsi/FB2mgKcMQk0vvLLMoTFzSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOz7yC%2FbtrKHcvvLsi%2FFB2mgKcMQk0vvLLMoTFzSK%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;355&quot; height=&quot;596&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b91ce7fc-43ff-4a33-954d-be5478abe4f8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e2cf8f20-3f32-43d2-ba01-58e44cf35b19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;성공적으로 1ETH를 전송했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-09563f9b-f59a-4dda-a6e6-7ece17b2caae&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8dd23e50-7a3f-45c8-94b1-7c85a2777f8d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트에 구현한 balanceOf 함수를 이용해서 스마트 컨트랙트의 이더리움 잔액 조회를 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fa902b2f-9e98-432f-b930-3559eec2b641&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7ciwT/btrKHUukbDi/Zo2wV9kYuZLe2uvvcWpFU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7ciwT/btrKHUukbDi/Zo2wV9kYuZLe2uvvcWpFU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7ciwT/btrKHUukbDi/Zo2wV9kYuZLe2uvvcWpFU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7ciwT%2FbtrKHUukbDi%2FZo2wV9kYuZLe2uvvcWpFU1%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;292&quot; height=&quot;294&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5c833c2c-fcd5-4779-b09b-f4cca21b6b52&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-37c32947-a779-4675-b399-60bb532347b1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 컨트랙트에 1ETH가 조회되는 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d8da030f-a351-4c61-b5ca-6144adffc541&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-34a1e918-4b2c-458c-970c-156cf8d964e5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;payable 키워드는 receive() 뿐 아니라 생성자(constructor) 또는 다른 함수에도 포함할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6b4ef0bd-2eb7-4b98-931a-447b06736790&quot;&gt;
&lt;pre id=&quot;code_1661639720571&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.10;

contract Transfer {
    uint public amount = 0;
    
    constructor () payable {
        amount = msg.value;
    }

    receive() external payable {}

    function balanceOf(address payable to) external view returns(uint) {
        return to.balance;
    }

    function transfer(address payable to, uint _amount) external {
        to.transfer(_amount);
    }

    function test() public payable {
        amount = msg.value;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f588a49d-7d7a-4375-b1b3-f7661db9210a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9ce4efcf-cf2a-4946-9e35-4991ab2c1857&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;payable로 지시된 함수는 remix 기준으로 다른 형태의 버튼UI로 표기됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7752c3cd-9deb-4e14-8636-8555f4bd331e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;631&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAcm4W/btrKIyEBbIf/3LH4dTkjoUeK7ZGLLK4hKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAcm4W/btrKIyEBbIf/3LH4dTkjoUeK7ZGLLK4hKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAcm4W/btrKIyEBbIf/3LH4dTkjoUeK7ZGLLK4hKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAcm4W%2FbtrKIyEBbIf%2F3LH4dTkjoUeK7ZGLLK4hKk%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;773&quot; height=&quot;631&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;631&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a182d2db-d19c-408a-992d-f04be82dd86e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5b01e924-0623-42fa-a142-f436b593e3d5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Deploy 버튼을 보면 적색으로 표시됩니다. Deploy 버튼은 constructor()에 영향을 받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-96422ae8-b627-4562-80bf-5d87d8fce3c3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-278c396e-220f-4d17-8c1d-d3477faf236c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;remix는 트랜잭션을 발생할 때 이더리움을 전송해야 한다면 녹색으로 표시한 VALUE 영역에 트랜잭션을 발생할 때 전송할 이더리움을 설정할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f1678e88-5ed6-4e7d-a4ca-63caf7dfe915&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKiCF1/btrKJ4QJldw/0zG5S9Ev4njG3bXDKIZYf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKiCF1/btrKJ4QJldw/0zG5S9Ev4njG3bXDKIZYf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKiCF1/btrKJ4QJldw/0zG5S9Ev4njG3bXDKIZYf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKiCF1%2FbtrKJ4QJldw%2F0zG5S9Ev4njG3bXDKIZYf0%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;773&quot; height=&quot;645&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-517c7c00-f738-4c8a-8a31-c2fd14d3c813&quot;&gt;
&lt;pre id=&quot;code_1661639732054&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;배포된 컨트랙트 주소: 0x29bbaC9A81b55a20E32aF944641559788207390a&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-529cc13e-3b75-4932-9ad2-b0a936842059&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6d9a0447-03e0-4d9c-b09a-e561f0df2697&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;VALUE에 1이더를 설정하고 Deploy 버튼을 눌렀습니다. 배포된 컨트랙트의 balanceOf를 이용하여 해당 컨트랙트의 이더리움 잔액을 확인하면 1이더가 있음을 확인할 수 있습니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-50ccb0cd-ed8e-4781-aa93-91f71f27a775&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;msg 객체를 이용하여 누가 호출했고, 얼마의 이더를 전송했는지 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a5b85d66-947c-4b9b-aeb0-b816ab81841f&quot;&gt;
&lt;pre id=&quot;code_1661639738095&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;msg.sender: 호출자
msg.value : 전송한 이더리움 양&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-45a004e8-2b2c-44e6-8051-0706252556ac&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7c68305c-5ce7-4f4c-b414-a6167b6775ab&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약, test() 함수를 호출 할 때 value를 입력하고 호출하면 해당 컨트랙트로 입력한 이더리움 양 만큼 전송을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-96d62575-f369-444d-a376-945f96b8d29c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 출금 가능한 스마트 컨트랙트 만들기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-9c4562d6-31c4-4408-afe4-9cec604310c9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 컨트랙트에 있는 1ETH를 transfer() 함수를 호출하여 다른 주소로 전송할 수 있습니다. transfer()는 address payable에서 제공하는 메서드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2df7596b-06e1-485c-a917-d0a0aa5d6f55&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0bdf5464-93ae-4f84-9e4a-a13d51a3d105&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 배포한 스마트 컨트랙트 코드에서 구현한 transfer() 함수를 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-684d07cc-7f16-4d92-a04c-367d70229ce9&quot;&gt;
&lt;pre id=&quot;code_1661639761856&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function transfer(address payable to, uint _amount) external {
    to.transfer(_amount);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bdb2188f-4898-41cd-bec1-b35225499c1a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-03506c3c-65d5-4c51-930e-9cbacb0ad726&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 만든 transfer() 함수는 2개의 인자를 전달받습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5b851c87-ec95-45ab-a863-eb1fb0af4b49&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-79d6f63d-bcab-4d60-8fcd-be8ac144d3cd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 인자인 to는 이더를 전송받을 주소입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0d702ee0-f3b5-43f2-9ee0-68f33f648e1a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 번째 인자인 _amount는 전송할 이더입니다. 이더리움은 decimals가 18이므로 1이더를 전송하기 위해선 1000000000000000000 만큼 전송해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fc91b84e-d092-4956-8abd-d9341eb38742&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9ee21b1b-30dd-4c5a-89e2-bcd7b26d758b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;597&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cikPbZ/btrKGRkL1K5/M1MLmHW5t7tbd0LmIwwVMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cikPbZ/btrKGRkL1K5/M1MLmHW5t7tbd0LmIwwVMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cikPbZ/btrKGRkL1K5/M1MLmHW5t7tbd0LmIwwVMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcikPbZ%2FbtrKGRkL1K5%2FM1MLmHW5t7tbd0LmIwwVMk%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;354&quot; height=&quot;597&quot; data-origin-width=&quot;354&quot; data-origin-height=&quot;597&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-93bc37cb-831b-4845-902e-e3310da2895d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9a452bca-70c8-464e-b160-4c91c72be409&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트의 1ETH중 0.5ETH 만큼 전송해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-47d2ba01-896d-4223-843d-8e15cc2a5060&quot;&gt;
&lt;pre id=&quot;code_1661639770056&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;to: 0xF3133758a5b12c99bdF762F93b86239a7Ef167f6
value: 0.5ETH (500000000000000000Wei)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a9fd6c8e-765a-42b5-a829-2af36434d19b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;286&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0GOQq/btrKGR6bfsG/6kYKBvOPkIu4mObiKkmIz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0GOQq/btrKGR6bfsG/6kYKBvOPkIu4mObiKkmIz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0GOQq/btrKGR6bfsG/6kYKBvOPkIu4mObiKkmIz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0GOQq%2FbtrKGR6bfsG%2F6kYKBvOPkIu4mObiKkmIz0%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;286&quot; height=&quot;530&quot; data-origin-width=&quot;286&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c505846a-209a-4f82-8d4e-4bed98a570c0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e40fe836-0e7e-4788-8aa6-f6ba1286944c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;transact 버튼을 누르면 트랜잭션이 발생하기 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1df862c5-095d-48fe-bcf3-5a32d66a4292&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YVSL2/btrKJ617bWi/34wddkpXwG9GI6Z7rNVP90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YVSL2/btrKJ617bWi/34wddkpXwG9GI6Z7rNVP90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YVSL2/btrKJ617bWi/34wddkpXwG9GI6Z7rNVP90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYVSL2%2FbtrKJ617bWi%2F34wddkpXwG9GI6Z7rNVP90%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;773&quot; height=&quot;645&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9ac76a1b-b39b-4e60-8688-921df45a6fe4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f56c9562-3408-4d8d-a5bd-de6ed6e6b17c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 컨트랙트 코드를 정상적으로 실행하지 못합니다. 그 이유는 출금을 할 경우에도 해당 함수에 payable이 붙어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f7128645-cd08-4be1-878b-53581da073bb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yaEGi/btrKLaJYiKO/8aQGc6jpK9VlcsUIBoSLHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yaEGi/btrKLaJYiKO/8aQGc6jpK9VlcsUIBoSLHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yaEGi/btrKLaJYiKO/8aQGc6jpK9VlcsUIBoSLHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyaEGi%2FbtrKLaJYiKO%2F8aQGc6jpK9VlcsUIBoSLHk%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;773&quot; height=&quot;645&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1d1652f6-9f98-493c-ae35-aafe13750716&quot;&gt;
&lt;pre id=&quot;code_1661639780537&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;배포된 컨트랙트 주소: 0x117c47cf20Cd24A88830f63204149A8229E7e269&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c221b540-6f7c-46fa-b476-df189beb73fd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-bde72b33-da59-4ce4-acee-578adc2daa45&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트의 이더를 다른 주소로 전송해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8a0ef12b-9158-4078-917a-e47f9dd4c028&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9214265e-ccb9-4a72-9a75-9818a007eadb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;353&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bndbcI/btrKK9xxHtx/Ghw0j8KdwnO7jSNyNSfNCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bndbcI/btrKK9xxHtx/Ghw0j8KdwnO7jSNyNSfNCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bndbcI/btrKK9xxHtx/Ghw0j8KdwnO7jSNyNSfNCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbndbcI%2FbtrKK9xxHtx%2FGhw0j8KdwnO7jSNyNSfNCk%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;353&quot; height=&quot;596&quot; data-origin-width=&quot;353&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5493d80f-4daf-419f-b334-cabdae070597&quot;&gt;
&lt;pre id=&quot;code_1661639789137&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;to: 0x84A220f3bF83883eE93793F05506Ba512AfcBCCf
value: 0.5ETH (500000000000000000Wei)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8c61751b-741d-4e4d-94ed-8941a1907fe1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;645&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N1QhS/btrKJ6HOZTu/BoAYWmgnMySCzorB7GqdW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N1QhS/btrKJ6HOZTu/BoAYWmgnMySCzorB7GqdW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N1QhS/btrKJ6HOZTu/BoAYWmgnMySCzorB7GqdW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN1QhS%2FbtrKJ6HOZTu%2FBoAYWmgnMySCzorB7GqdW1%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;773&quot; height=&quot;645&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;645&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-10925dec-ca7a-47d7-828a-b050c7f4561f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-67555085-149a-4022-8218-d704bc94ffcc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트에서 metamask에 존재하는 지갑으로 이더리움 전송을 완료했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-f6691096-fccb-4e81-9404-3220f02508e9&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 스마트 컨트랙트에서 스마트 컨트랙트로 이더리움 전송&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-0f9c7c7e-c120-4a47-afb5-72fdb4ccdad4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 transfer()를 이용하여 다른 주소로 이더리움을 전송하는 과정을 보았습니다. 컨트랙트 주소도 주소이기 때문에 to가 컨트랙트 주소일 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-63515c4b-3341-4f02-8798-d99e1b258c80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0629c89c-c987-45fc-83c0-f6189a85a48d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그런데 receive()가 아니라 앞에서 test() payable 형태로 구현되어 있는 스마트 컨트랙트가 있을때 해당 컨트랙트의 test()를 호출하면서 이더리움을 전송하기 위해선 다음과 같이 해야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c52b244e-9b8d-438d-a702-676670d3d153&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0bca41e1-e0b7-4c76-af7d-1f39d0fb2541&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661639809321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// test() payable 컨트랙트가 정의된 solidity 파일 이름
import './Transfer.sol';

contract TransferBridge {
  function transfer(address _to, uint _amount) external {
    Transfer(_to).test{value: _amount}();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-abc54243-6311-4460-a02e-07560ccfc9a9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 형태로 컨트랙트에서 배포된 다른 컨트랙트의 함수를 호출할 수 있습니다. 함수이름과 () 사이에 {value: amount}를 포함하여 해당 기능을 수행할 수 있습니다. TransferBridge로 배포한 스마트 컨트랙트의 transfer를 호출하면 해당 컨트랙트에 있는 _amount 이더리움 만큼 Transfer로 전송합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-71e06f85-c816-45a1-8f84-e4af0e2e7b70&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 출금패턴&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-a8a29bd6-d149-4e9d-a149-284c8fdd9540&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출금패턴은 스마트 컨트랙트의 이더리움을 외부로 전송하는 코드를 분리해서 작성하는 패턴입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-8f840e5d-098b-413e-85e6-86f3202a8e6f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 출금패턴이 필요한 이유&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-890b3014-455a-46ac-ad91-a98de7064a5a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컨트랙트는 transfer()하는 대상이 외부 소유 계정(EOA), 컨트랙트 계정(CA)가 있습니다. transfer()를 호출할 때 EOA로 전송한다면 문제되지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cfafcddb-3685-47b8-b82a-f0c7e5ca3101&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 receive() payable 또는 payable이 존재하지 않는 함수로 이더를 전송하려고 시도한다면? 반대로 컨트랙트의 특정 함수에 대해서만 이더 전송을 시도한다면 EOA는 함수가 존재하지 않기 때문에 문제가 발생할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-18f4febd-b6f1-4f54-b5c4-6875e1407c71&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 출금 패턴을 적용하지 않은 코드 살펴보기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d4312eae-df53-4b5d-86f1-f9fac830fcde&quot;&gt;
&lt;pre id=&quot;code_1661639835771&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.10;

contract NonWithdrawalContract {
    address payable public richest;
    uint public mostSent = 0;

    constructor() payable {
        richest = payable(msg.sender);
        mostSent = msg.value;
    }

    function becomeEther () external payable {
        if (msg.value &amp;gt; mostSent) {
            // richest가 receive()가 없는 컨트랙트라고 가정해보자!
            payable(richest).transfer(mostSent);
            richest = payable(msg.sender);
            mostSent = msg.value;
        } 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e131fda0-2930-4daf-a3f1-c7e2091c42a5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4d2e499f-4723-4138-9cb0-582527972366&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 코드는 출금패턴을 적용하지 않은 코드입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d14c8154-3bfb-4810-a3ec-dcb901a50dd7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;becomeEther() 함수만 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3c140083-fe9b-41e0-b969-503e91cf3578&quot;&gt;
&lt;pre id=&quot;code_1661639854851&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function becomeEther () external payable {
        if (msg.value &amp;gt; mostSent) {
            // richest가 receive()가 없는 컨트랙트라고 가정해보자!
            payable(richest).transfer(mostSent);
            richest = payable(msg.sender);
            mostSent = msg.value;
        } 
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-33e13ffb-9913-4e09-80f6-36cbe3c6939d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ff47189f-1c29-4dc8-8a6c-313b3edf3943&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 코드가 잘 동작하다가 receive()를 구현하지 않은 컨트랙트 주소가 richest에 저장되어 있다면? &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1dd9d66d-1d64-4a45-8586-467cc61421d3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c72bb4b0-a0d8-4d02-b9b0-294c8b54a858&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 함수는 어디선가 richest를 바꾸지 않는다면 영영 정상적인 호출을 하지 못합니다. 또는 특정 컨트랙트의 함수를 호출하는 형태로도 작성할 수 있겠죠? 이땐 전송하는 목적지 주소가 반드시 특정 함수가 구현된 컨트랙트 주소여야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-72724ad1-4b2b-47bf-bfd8-ec0be602db1d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dac89485-bf93-4594-8081-8152ccd32e2d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 스마트 컨트랙트는 주소만 가지고 앞의 여러 상황을 알 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-adbbf641-ef5f-4452-a7f5-110a590b4c15&quot;&gt;
&lt;pre id=&quot;code_1661639867140&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. transfer()를 호출하는데 receive()를 구현한 스마트 컨트랙트 주소가 맞는지?
2. 다른 스마트 컨트랙트에 구현된 함수() payable로 전송하는데 스마트 컨트랙트 주소가 맞는지? 
   또는 함수 payable이 정상적으로 구현되어 있는지?&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d0fb50f3-a1d5-4361-b1e5-716a0093f2dd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9f50274c-b318-4b11-910a-3804418c0fa5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 복합적인 상황을 다 검사할 순 없습니다. 물론! 불가능한건 아니지만 너무 비효율적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-65ce062c-fc47-4d11-8e09-049031cfbcac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a4654d9c-1fc4-4669-8137-64805cf3e191&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 비효율이란? 쓸데없는 검사를 위해 연산량이 올라가고 연산량이 증가하면 수수료가 많이 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-f8b16b33-e35b-40ab-a7ca-5c7e9382be99&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 출금 패턴 적용한 코드 살펴보기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-b0c6bc60-0a4a-40b0-b9b5-70d2d2d82010&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출금 패턴은 아주 간단합니다. 앞에서 입/출금 만들면서 transfer() 함수를 이용하여 특정 함수에 출금에 관련한 코드밖에 없었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7083bbf3-7f72-4290-a7e0-e976022f7269&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c7c801e8-1b4d-4472-b526-726cca4a2257&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;출금 패턴은 출금만 담당하는 코드를 별도로 분리하여 관리하는 것을 의미합니다. NonWithdrawalContract 여기선 becomeEther() 함수에 입금/출금 기능이 같이 있기 때문에 출금에 문제가 생기면 입금도 사용할 수 없습니다. 여기선 입금코드만 있지만 입금 외 여러가지 로직을 포함할 수 있겠죠?&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-95b5075f-c545-4a9d-bb88-db83050ebd6e&quot;&gt;
&lt;pre id=&quot;code_1661639884413&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.10;

contract WithdrawalContract {
    address payable public richest;
    uint public mostSent;

    mapping (address =&amp;gt; uint) pendingWithdrawals;

    constructor() public payable {
        richest = payable(msg.sender);
        mostSent = msg.value;
    }

    function becomeEther() public payable {
        if (msg.value &amp;gt; mostSent) {
            pendingWithdrawals[richest] += msg.value;
            richest = payable(msg.sender);
            mostSent = msg.value;
        }
    }

    function withdraw() public {
        uint amount = pendingWithdrawals[msg.sender];
        // 리엔트란시(re-entrancy) 공격을 예방하기 위해
        // 송금하기 전에 보류중인 환불을 0으로 기억해 두십시오.
        pendingWithdrawals[msg.sender] = 0;
        payable(msg.sender).transfer(amount);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f5c62e76-e718-4768-bd53-73f493237485&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6407a2fd-1faf-4eb0-8539-c755d5d6a270&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;becomeEther()에서 호출한 transfer()를 withdraw() 함수로 옮겨줍니다. 대신 becomeEther()는 이더를 받는 함수이므로 mapping 타입을 이용하여 이더를 받은 주소를 관리합니다. 이렇게 하면 becomeEther()는 항상 성공하며, withdraw()는 msg.sender가 다음 조건을 만족하지 않는 경우에 대해서만 에러가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a06c190c-00ca-46c4-bc8d-15573f4bd9b7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;1.&lt;/span&gt; &lt;span style=&quot;color: #df4a68;&quot;&gt;transfer&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;)&lt;/span&gt;를 호출하는데 &lt;span style=&quot;color: #df4a68;&quot;&gt;receive&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;)&lt;/span&gt;를 구현한 스마트 컨트랙트 주소가 맞는지&lt;span style=&quot;color: #a77f71;&quot;&gt;?&lt;/span&gt; &lt;span style=&quot;color: #e57523;&quot;&gt;2.&lt;/span&gt; 다른 스마트 컨트랙트에 구현된 &lt;span style=&quot;color: #df4a68;&quot;&gt;함수&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;)&lt;/span&gt; payable로 전송하는데 스마트 컨트랙트 주소가 맞는지&lt;span style=&quot;color: #a77f71;&quot;&gt;?&lt;/span&gt; 또는 함수 payable이 정상적으로 구현되어 있는지&lt;span style=&quot;color: #a77f71;&quot;&gt;?&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-88b5411b-9e19-4bdf-9d24-27de132d5b66&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-cf18307c-ca24-4001-a9e7-d0cbd710bd34&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● truffle 출금 패턴 테스트 코드 작성&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-09577420-4638-44ac-9c7b-46084cc8e433&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막으로 truffle을 이용하여 출금 패턴을 적용하지 않은 코드에 대해서 에러가 나는 상황을 구현하고 이를 테스트하는 코드를 작성해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a8794588-dc15-4e2b-a1d2-91978f739f73&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 정확히 이해한다면, 출금 패턴을 적용하면 에러가 나지 않는 상황을 이해할 수 있을겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-dffa1c37-3324-430b-aba9-8c9c16e08e67&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 프로젝트 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-8b41b578-37d1-47ef-a0b8-c59f91ca72fd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;truffle은 init 명령어로 프로젝트를 생성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-12d364a8-5376-4626-9527-9213bfacfb84&quot;&gt;
&lt;pre id=&quot;code_1661639909340&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir withdraw-patterns

$ cd withdraw-patterns

$ truffle init&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-35546cc1-9763-4145-bac5-f9cd97836939&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d5231220-80cb-42a0-bedc-4a4e47e84d34&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;error assertions 테스트와 이더리움 단위 변환을 위해 다음 2개의 라이브러리를 설치합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-337f9c2a-d64b-425e-a51c-a02f3f88eaca&quot;&gt;
&lt;pre id=&quot;code_1661639915573&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save truffle-assertions
$ npm install --save web3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a72c466d-7180-466f-85bc-01729c68d09b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-34e6322d-4d0d-49d6-aa29-5f09631826ec&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음으로 &lt;/span&gt;&lt;span style=&quot;color: #007433;&quot;&gt;&lt;i&gt;&lt;b&gt;truffle-config.js&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;span&gt;을 다음과 같이 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-282cfb90-7652-4271-a7e3-54102efe26ef&quot;&gt;
&lt;pre id=&quot;code_1661639928175&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {
  networks: {
    dev: {
     host: &quot;127.0.0.1&quot;,     
     port: 8545,            
     network_id: &quot;*&quot;,       
    },
  },
  mocha: {},

  compilers: {
    solc: {
      version: &quot;0.8.10&quot;,  
     
    }
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7aac45bb-7062-4188-adc9-d96c462599c1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4e153dd7-b9f3-4fd8-8152-513581afeaf8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;networks는 스마트 컨트랙트를 배포할 환경 정보를 관리합니다. networks는 json 형태로 여러 환경을 관리할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-83d46d1f-7cd7-406d-be00-55b561c58110&quot;&gt;
&lt;pre id=&quot;code_1661639937524&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module.exports = {
  networks: {
    dev: {
     host: &quot;127.0.0.1&quot;,     
     port: 8545,            
     network_id: &quot;*&quot;,       
    },
    propd: {
     host: &quot;192.168.1.1&quot;,     
     port: 8546,            
     network_id: &quot;*&quot;,       
    },
  },
  mocha: {},

  compilers: {
    solc: {
      version: &quot;0.8.10&quot;,  
     
    }
  }
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-20487b86-0d50-46d4-bbdd-58a224e542b4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d65d553b-2eda-456d-8fbf-21f42f4fba60&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 시나리오 설계&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d50a1e61-4054-482a-97c7-de9b50e966d5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 부분은 저도 처음에 출금 패턴 테스트 코드를 작성하기 위해 시간이 다소 오래걸렸던 부분입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4a03a9cb-3ae1-4f8d-8231-23f3731f8ca2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-266e5fb1-8f78-4704-8b75-f220ac250e43&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;1. 3개의 컨트랙트를 준비한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b4d19971-8806-435b-afd6-0f791bb75755&quot;&gt;
&lt;pre id=&quot;code_1661639949221&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NonWithdrawalContract: 출금패턴을 적용하지 않은 컨트랙트

PayableContract: receive()가 구현된 컨트랙트

NonPayableContract: receive()를 구현하지 않은 컨트랙트&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-020957e8-e88f-40f3-a64c-90c96b50b939&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-426dd8f7-ea53-49c1-9827-03f90b1e3e65&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;2. NonWithdrawalContract 배포&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9bad7402-6e23-4545-b54b-7744a94b1d7e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;3. PayableContract 배포 - 배포할 때 2ETH를 전송한다. constructor()는 payable를 포함합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1c0ac978-d8a9-4279-8f13-1925ddd82c00&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;4. NonPayableContract 배포 - 배포할 때 2ETH를 전송한다. receive()는 constructor()는 payable를 포함합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9e34d215-7479-4ae0-9ab3-92de0937a171&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d5af1a19-3b53-471c-9870-4e4dca6684d0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;5. richest가 PayableContract일때와 NonPayableContract인 상황 만들기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-af6b3a37-f224-490d-bc69-e7038da8f46b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-26c77522-66d9-434a-a02a-7d45d70866d6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대략적인 시나리오는 이정도 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f3b03a99-ba8f-49dc-9f35-a1378ef527b8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fa14fd20-1850-4319-8ff1-ceff31a709fd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각각의 시나리오는 truffle에선 다음과 같이 작업할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-832be81a-90cc-4216-b1e4-e09b3b40ecf8&quot;&gt;
&lt;pre id=&quot;code_1661639962294&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contracts: 1번 

migrations: 2번, 3번, 4번

test: 5번&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-80196551-b018-4b6b-bd66-317925339cd5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f19c27df-f935-4744-85dd-8d59068772d8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;truffle 프로젝트를 생성하면 3개의 디렉터리를 생성합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bab259b3-7e9a-444f-b51b-bc41369d16f5&quot;&gt;
&lt;pre id=&quot;code_1661639968325&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contracts: 스마트 컨트랙트 코드 관리
migrations: 배포관리
test: 실질적인 동작을 수행하며, 정상적으로 동작하는지 테스트 가능&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7d3ef12f-dc68-42e4-8f43-80f5c0576c48&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-820ae013-f9a3-4677-b0a3-dd16014854ad&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 스마트 컨트랙트 코드 작성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a7fe47a9-4074-4615-b827-8af2a7ba408b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트 코드는 contracts 아래에서 관리합니다. 3개의 코드를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-8cd0c4ba-85b1-4e78-8630-4ed55688957c&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ NonWithdrawalContract.sol&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f454d2b7-e73a-4828-a248-7c82712a5921&quot;&gt;
&lt;pre id=&quot;code_1661639990822&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.10;

contract NonWithdrawalContract {
    address payable public richest;
    uint public mostSent = 0;

    constructor() payable {
        richest = payable(msg.sender);
        mostSent = msg.value;
    }

    function becomeEther () external payable {
        if (msg.value &amp;gt; mostSent) {
            // richest가 receive()가 없는 컨트랙트라고 가정해보자!
            payable(richest).transfer(mostSent);
            richest = payable(msg.sender);
            mostSent = msg.value;
        } 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-69ded0c6-990b-4248-a048-283304717c56&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-72c171be-8062-4717-b09c-ce3c05312c4f&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ PayableContract.sol&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1661640012891&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.10;

import './NonWithdrawPattern.sol';

contract PayableContract {
  constructor () payable {}

  receive () external payable{}

  function send(address _to, uint _amount) external {
    NonWithdrawalContract(_to).becomeEther{value: _amount}();
  }

  function balanceOf() public view returns(uint) {
      return payable(this).balance;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-da228c2c-878e-44dd-9a17-936fc8ce2556&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-084b5567-6849-4d32-b9b9-4cf79c6ff9e6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-055d8461-ac55-4ab6-8ad0-0dc62ca03b6d&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ NonWithdrawPattern.sol&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0f7aae65-f18c-4570-9de4-87280ad20a93&quot;&gt;
&lt;pre id=&quot;code_1661640019472&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: GPL
pragma solidity 0.8.10;

import './NonWithdrawPattern.sol';

contract NonPayableContract {
  constructor () payable {}

  function send(address _to, uint _amount) external {
    NonWithdrawalContract(_to).becomeEther{value: _amount}();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d129460b-61d0-4db1-bae7-4fd0b9306967&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ade47a37-2754-4e53-a57c-95a4d7ac195d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 작성된 코드는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;compile&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 명령어를 이용하여 컴파일 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-65eaea13-8aa8-44a1-a9e5-bea38f952a64&quot;&gt;
&lt;pre id=&quot;code_1661640030359&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle compile

Compiling your contracts...
===========================
&amp;gt; Compiling ./contracts/Migrations.sol
&amp;gt; Compiling ./contracts/NonPayableContract.sol
&amp;gt; Compiling ./contracts/NonWithdrawPattern.sol
&amp;gt; Compiling ./contracts/PayableContract.sol
&amp;gt; Compiling ./contracts/WithdrawPattern.sol
&amp;gt; Compilation warnings encountered:

    Warning: Visibility for constructor is ignored. If you want the contract to be non-deployable, making it &quot;abstract&quot; is sufficient.
  --&amp;gt; project:/contracts/WithdrawPattern.sol:10:5:
   |
10 |     constructor() public payable {
   |     ^ (Relevant source part starts here and spans across multiple lines).


&amp;gt; Artifacts written to /Users/jeongtaepark/Desktop/withdraw-patterns/build/contracts
&amp;gt; Compiled successfully using:
   - solc: 0.8.10+commit.fc410830.Emscripten.clang&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7558c740-a243-4584-b3aa-ef703a794c05&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f4ab6ab8-9adb-40b4-a923-84374916b023&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 작성한 코드가 문제 없으면 다음과 같이 build 디렉터리가 생성되며, 배포를 위한 준비가 끝납니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5afd357e-9f66-40ea-b2cd-9f18fce3ba51&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e14d394b-73e8-44a4-a746-1bc382aa5669&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아마 0.8.10 기준으로 warning이 하나 뜨게 되는데 이건 추후에 별도로 다뤄보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-6a49c09c-2877-48bb-a5ca-649b0830205c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 배포&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e9e156c0-102e-4780-b9ad-39e850ebf908&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배포는 migrations 아래에서 관리합니다. 3개의 컨트랙트를 배포하는 코드를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cbc742b2-c463-4eb2-9e20-cf3975b573e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4f6c9329-ba3c-478a-af58-73726dbba112&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;web3의 utils를 이용하면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;이더단위&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 편하게 바꿀 수 있습니다. 굳이 0을 17~18번 작성하지 않아도 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a1b691fa-0454-4bc5-9193-0a7d2637a3be&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;SE-0a8e8977-0573-4ef0-a203-751b11110c3c&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 2_PayableContract_migration.js&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-20c84d74-b220-491d-8fea-1f05ba85b461&quot;&gt;
&lt;pre id=&quot;code_1661640069923&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const PayableContract = artifacts.require(&quot;PayableContract&quot;);
const web3 = require('web3');

module.exports = function (deployer) {
  deployer.deploy(PayableContract, {value: web3.utils.toWei(&quot;2&quot;, &quot;ether&quot;)});
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8f37d3d2-8d9b-435e-bd80-68717bfb70ec&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fa7abef0-d98f-46a4-9c2a-138bf7c8aa35&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;truffle은 트랜잭션 발생할 때 마지막 인자에 {value: amount, from: address}를 전달하여 트랜잭션 정보를 포함할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-c8a6bd11-a761-44fc-aafd-517320715543&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 3_NonPayableContract_migration.js&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b7adb6e2-dd9e-4c8d-94e0-cd91706cc877&quot;&gt;
&lt;pre id=&quot;code_1661640081762&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const NonPayableContract = artifacts.require(&quot;NonPayableContract&quot;);
const web3 = require('web3');

module.exports = function (deployer) {
  deployer.deploy(NonPayableContract, {value: web3.utils.toWei(&quot;2&quot;, &quot;ether&quot;)});
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0e8f7056-6e98-4236-9e7b-36fa05d44396&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-27c131a7-0afc-4dd6-9588-0adcd30d7560&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 4_NonWithdrawContract_migration.js&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3428f6e4-222d-4372-ade9-e5842df7cac4&quot;&gt;
&lt;pre id=&quot;code_1661640088662&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const NonWithdrawalContract = artifacts.require(&quot;NonWithdrawalContract&quot;);
const web3 = require('web3');

module.exports = function (deployer) {
  deployer.deploy(NonWithdrawalContract);
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e0c57fa0-85de-42f7-a417-911d1aa99ad3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f59727fb-454a-4807-b68b-010a216ed26d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 우리는 배포를 위한 코드 작성을 마쳤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9418f793-361e-4fd7-aaa2-ba981b34969c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dec24623-0e66-4b10-85ef-4822bc8372c9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;truffle은 migrate 명령어를 이용하여 스마트 컨트랙트를 배포할 수 있습니다. remix에서 deploy를 누르는 과정으로 이해하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c94f7bf8-d056-45d3-9089-b415a03050d8&quot;&gt;
&lt;pre id=&quot;code_1661640095630&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle migrate --network dev&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a43e70e-a989-49f8-8897-b18e7e990418&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b71b3523-297d-4420-9fab-1b07b535293b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이떄 --network 옵션으로 dev를 주게 되는데 이건 truffle-comfig.js의 network에 정의한 dev로 관리중인 정보에 배포한다는 의미입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-20b4f835-0ff3-4083-90ad-98ad28c6df7c&quot;&gt;
&lt;pre id=&quot;code_1661640106807&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Compiling your contracts...
===========================
&amp;gt; Everything is up to date, there is nothing to compile.



Starting migrations...
======================
&amp;gt; Network name:    'dev'
&amp;gt; Network id:      1639353530182
&amp;gt; Block gas limit: 6721975 (0x6691b7)


1_initial_migration.js
======================

   Deploying 'Migrations'
   ----------------------
   &amp;gt; transaction hash:    0xaaf21cb53b1b6cf831b871bc8904bf878d38819e2a480169c5365dbc6c69a5be
   &amp;gt; Blocks: 0            Seconds: 0
   &amp;gt; contract address:    0xeb68a074e9C1A482f816202035ce550d30e25253
   &amp;gt; block number:        15
   &amp;gt; block timestamp:     1639359582
   &amp;gt; account:             0xF3133758a5b12c99bdF762F93b86239a7Ef167f6
   &amp;gt; balance:             94.96525818
   &amp;gt; gas used:            248854 (0x3cc16)
   &amp;gt; gas price:           20 gwei
   &amp;gt; value sent:          0 ETH
   &amp;gt; total cost:          0.00497708 ETH


   &amp;gt; Saving migration to chain.
   &amp;gt; Saving artifacts
   -------------------------------------
   &amp;gt; Total cost:          0.00497708 ETH


2_PayableContract_migration.js
==============================

   Deploying 'PayableContract'
   ---------------------------
   &amp;gt; transaction hash:    0xaef5081a44fe3f3f191451b733a95356c19de138109903afecb21e108b480d76
   &amp;gt; Blocks: 0            Seconds: 0
   &amp;gt; contract address:    0x634B0759c0d13599879b97B4f38eaD7A7cB5758D
   &amp;gt; block number:        17
   &amp;gt; block timestamp:     1639359583
   &amp;gt; account:             0xF3133758a5b12c99bdF762F93b86239a7Ef167f6
   &amp;gt; balance:             92.96091778
   &amp;gt; gas used:            174507 (0x2a9ab)
   &amp;gt; gas price:           20 gwei
   &amp;gt; value sent:          2 ETH
   &amp;gt; total cost:          2.00349014 ETH


   &amp;gt; Saving migration to chain.
   &amp;gt; Saving artifacts
   -------------------------------------
   &amp;gt; Total cost:          2.00349014 ETH


3_NonPayableContract_migration.js
=================================

   Deploying 'NonPayableContract'
   ------------------------------
   &amp;gt; transaction hash:    0x2ea04740632169ac427e93903b92700ccd879e79b71fc0b99bab23b826dbddc4
   &amp;gt; Blocks: 0            Seconds: 0
   &amp;gt; contract address:    0x6367D6059FbBd0c7832847d702588f01c6077cF1
   &amp;gt; block number:        19
   &amp;gt; block timestamp:     1639359583
   &amp;gt; account:             0xF3133758a5b12c99bdF762F93b86239a7Ef167f6
   &amp;gt; balance:             90.95737322
   &amp;gt; gas used:            149715 (0x248d3)
   &amp;gt; gas price:           20 gwei
   &amp;gt; value sent:          2 ETH
   &amp;gt; total cost:          2.0029943 ETH


   &amp;gt; Saving migration to chain.
   &amp;gt; Saving artifacts
   -------------------------------------
   &amp;gt; Total cost:           2.0029943 ETH


4_NonWithdrawContract_migration.js
==================================

   Deploying 'NonWithdrawalContract'
   ---------------------------------
   &amp;gt; transaction hash:    0xdd86457548e6d54915c626d51121e1d8286a9979aedc218540ea4ccf4c6d8959
   &amp;gt; Blocks: 0            Seconds: 0
   &amp;gt; contract address:    0x37892D4862c7Fce93752a5b8af8484dEEBFD3E3E
   &amp;gt; block number:        21
   &amp;gt; block timestamp:     1639359583
   &amp;gt; account:             0xF3133758a5b12c99bdF762F93b86239a7Ef167f6
   &amp;gt; balance:             90.95277612
   &amp;gt; gas used:            202342 (0x31666)
   &amp;gt; gas price:           20 gwei
   &amp;gt; value sent:          0 ETH
   &amp;gt; total cost:          0.00404684 ETH


   &amp;gt; Saving migration to chain.
   &amp;gt; Saving artifacts
   -------------------------------------
   &amp;gt; Total cost:          0.00404684 ETH


Summary
=======
&amp;gt; Total deployments:   4
&amp;gt; Final cost:          4.01550836 ETH&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3a962ad2-bfbd-4f24-bb36-c08f5b7d4785&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-05181e09-ee7e-491f-bba1-700b88c5a061&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 작성한 3개의 컨트랙트 배포를 정상적으로 마쳤습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e199bd3a-5e29-4f78-8543-ce0552a741d7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-35ba2dd3-04e7-4979-9787-234ad4abb237&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 항목의 contract address가 배포된 컨트랙트 주소입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c90e7c35-b653-48a0-a0c2-d20f541ffb93&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-81a81cdd-a775-4a38-9901-e70f5db1eecb&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 동작 확인하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a0f1f803-5ec7-459f-b744-a11e64ac1af1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;동작을 수행하고 확인하는 코드는 test 아래에서 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f527fab-b3d6-48dc-90f6-f8e6b03eaa92&quot;&gt;
&lt;pre id=&quot;code_1661640127013&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const PayableContract = artifacts.require(&quot;PayableContract&quot;);
const NonPayableContract = artifacts.require(&quot;NonPayableContract&quot;);

const NonWithdrawalContract = artifacts.require(&quot;NonWithdrawalContract&quot;);
const truffleAssert = require('truffle-assertions');

const web3 = require('web3');

describe(&quot;test&quot;, function(accounts) {
  
  before(async function () {
    /* 
      배포된 컨트랙트 가져오기, 
      1. 출금패턴 비적용, 
      2. 이더수신 불가능, 
      3. 이더수신 가능 
    */
    this.instance = await NonWithdrawalContract.deployed(); 
    this.nonPayableContract = await NonPayableContract.deployed();
    this.payableContract = await PayableContract.deployed();
  })

  it('최고 전송자, 금액 바뀌는 경우 by PayableContract', async function() {
    const to = NonWithdrawalContract.address;
    const amount = web3.utils.toWei('0.1', 'ether');
    await this.payableContract.send(to, amount); 
    const richest = await this.instance.richest();
    const mostSent = await this.instance.mostSent();
    
    assert.strictEqual(richest, this.payableContract.address);
    assert.strictEqual(mostSent.toString(), amount);
  })
  
  it('최고 전송자가 바뀌지 않는경우 by NonPayableContract', async function() {
    const to = NonWithdrawalContract.address
    const amount = web3.utils.toWei('0.1', 'ether');
  
    await this.nonPayableContract.send(to, amount); 
    
    const richest = await this.instance.richest();
    const mostSent = await this.instance.mostSent();
    
    assert.strictEqual(richest, this.payableContract.address);
    assert.strictEqual(mostSent.toString(), amount);
  })
  
  it('최고 전송자가 바뀌는 경우 by NonPayableContract', async function() {
    const to = NonWithdrawalContract.address
    const amount = web3.utils.toWei('0.2', 'ether');
  
    await this.nonPayableContract.send(to, amount); 
    
    const richest = await this.instance.richest();
    const mostSent = await this.instance.mostSent();
    
    assert.strictEqual(richest, this.nonPayableContract.address);
    assert.strictEqual(mostSent.toString(), amount);
  })

  it('NonPayable -&amp;gt; Payable로 다시 바뀌는 경우: NonPayable에게 NonPayable.transfer 발생: 지금부터 NonWithdrawContract의 mostSent보다 높은 이더 전송시 에러', async function () {
    // 해당 케이스는 반드시 에러가 발생한다.
    // NonWithdrawalContract의 richest는 receive()가 구현되어 있지 않기 때문에 .transfer()가 정상동작 할 수 없다.
    // NonWithdrawalContract 해당 컨트랙트는 richest를 바꿀 수 있는 방법이 없기 때문에 더이상 동작하지 않는 코드가 된다.

    const to = NonWithdrawalContract.address;
    const amount = web3.utils.toWei('0.3', 'ether');
    const tx = this.payableContract.send(to, amount); 

    await truffleAssert.reverts(
      tx,
      'revert'
    );
  })

  it('에러1', async function () {
    const to = NonWithdrawalContract.address;
    const amount = web3.utils.toWei('0.4', 'ether');
    const tx = this.payableContract.send(to, amount); 

    await truffleAssert.reverts(
      tx,
      'revert'
    );
  })
  
  it('에러2', async function () {

    const to = NonWithdrawalContract.address;
    const amount = web3.utils.toWei('0.4', 'ether');
    const tx = this.payableContract.send(to, amount); 

    await truffleAssert.reverts(
      tx,
      'revert'
    );
  })

  it('에러3', async function () {
    const to = NonWithdrawalContract.address;
    const amount = web3.utils.toWei('0.4', 'ether');
    const tx = this.nonPayableContract.send(to, amount); 

    await truffleAssert.reverts(
      tx,
      'revert'
    );
  })
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-524a3ee9-d15e-4e2a-99be-1775c1b1f2e1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ec37eeb2-3097-4d6a-ab03-a101c4f4c9ab&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;동작을 수행하기 위해 test를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f82838e6-7252-4578-90b9-c5e6c7e3b832&quot;&gt;
&lt;pre id=&quot;code_1661640139198&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle test --network dev

Using network 'dev'.

Compiling your contracts...
===========================
&amp;gt; Everything is up to date, there is nothing to compile.

  test
    ✓ 최고 전송자, 금액 바뀌는 경우 by PayableContract (97ms)
    ✓ 최고 전송자가 바뀌지 않는경우 by NonPayableContract (87ms)
    ✓ 최고 전송자가 바뀌는 경우 by NonPayableContract (100ms)
    ✓ NonPayable -&amp;gt; Payable로 다시 바뀌는 경우: NonPayable에게 NonPayable.transfer 발생: 지금부터 NonWithdrawContract의 mostSent보다 높은 이더 전송시 에러 (267ms)
    ✓ 에러1 (66ms)
    ✓ 에러2 (80ms)
    ✓ 에러3 (77ms)

  7 passing (806ms)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-33d38c25-1ea3-4211-90b7-bb77948ef167&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f7c64983-23b7-4a4d-8506-aa60797676ad&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기선 7개의 항목에 대한 동작을 테스트합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cc9694d9-bcfd-4c12-8ca0-f5e92c550a22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-06b2ab84-d726-4127-92cc-fb25d377e9fb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각각의 테스트 항목이 무엇을 테스트 하는지 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-050bfa5f-fd1d-4407-a3f7-f560e30e5473&quot;&gt;
&lt;pre id=&quot;code_1661640150304&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;before(async function () {
    /* 
      배포된 컨트랙트 가져오기, 
      1. 출금패턴 비적용, 
      2. 이더수신 불가능, 
      3. 이더수신 가능 
    */
    this.instance = await NonWithdrawalContract.deployed(); 
    this.nonPayableContract = await NonPayableContract.deployed();
    this.payableContract = await PayableContract.deployed();
  })&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b8960617-7e40-470a-9c3a-30037c6fe89b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-64989789-156c-4ac3-97e7-4a74bb3b77bb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 코드는 우리가 배포한 컨트랙트를 가져오는 것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-6dd7b6ae-fedc-489b-9fa5-a29f2d326192&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ PayableOntract가 최고 전송자(richest)가 되는경우&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-50fbd434-b54f-436e-aeb5-2e7e5601b616&quot;&gt;
&lt;pre id=&quot;code_1661640178520&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;it('최고 전송자, 금액 바뀌는 경우 by PayableContract', async function() {
  const to = NonWithdrawalContract.address;
  const amount = web3.utils.toWei('0.1', 'ether');
  await this.payableContract.send(to, amount); 
  const richest = await this.instance.richest();
  const mostSent = await this.instance.mostSent();
  
  assert.strictEqual(richest, this.payableContract.address);
  assert.strictEqual(mostSent.toString(), amount);
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aba5ad7d-4f37-4a73-bdad-21197983ed65&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-070b82e3-15bf-46ee-b97d-0b8b5eadb6bc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;payableContract가 최초로 이더를 전송하기 때문에 최고 전송자가 됩니다. 이때 0.1ETH를 전송합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-75294c2b-3c76-448a-9439-ce5456e23827&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 최고 전송자(richest)가 바뀌지 않는경우&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1ea0f8a4-367e-4406-8b67-f4c2295e96a6&quot;&gt;
&lt;pre id=&quot;code_1661640185873&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;it('최고 전송자가 바뀌지 않는경우 by NonPayableContract', async function() {
  const to = NonWithdrawalContract.address
  const amount = web3.utils.toWei('0.1', 'ether');
  
  await this.nonPayableContract.send(to, amount); 
  
  const richest = await this.instance.richest();
  const mostSent = await this.instance.mostSent();
  
  assert.strictEqual(richest, this.payableContract.address);
  assert.strictEqual(mostSent.toString(), amount);
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3a8fb798-054f-4ea8-b8a0-a9a735ffc9e0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6bafe8ea-0f67-4cd7-9bfa-e785bfa9b86d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NonPayableContract가 이더를 전송하지만 현재 최고 전송자보다 더 많은 금액을 전송하지 않았기 때문에 바뀌지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-3f497eec-d09a-4d8d-bd41-43c06483c0df&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ NonPayableContract로 최고 전송자(richest)가 바뀌는 경우&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f8d99411-0a5a-4292-9f23-814df299a7e3&quot;&gt;
&lt;pre id=&quot;code_1661640195400&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;it('최고 전송자가 바뀌는 경우 by NonPayableContract', async function() {
  const to = NonWithdrawalContract.address
  const amount = web3.utils.toWei('0.2', 'ether');
  
  await this.nonPayableContract.send(to, amount); 
  
  const richest = await this.instance.richest();
  const mostSent = await this.instance.mostSent();
  
  assert.strictEqual(richest, this.nonPayableContract.address);
  assert.strictEqual(mostSent.toString(), amount);
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fce9572d-fbec-47ab-89ed-0c988fc703f9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e1a23989-06f9-4246-a0ce-09e586d4781c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NonPayableContract가 기존 최고 전송자보다 더 많은 ETH를 전송했기 때문에 최고 전송자가 바뀌고 기존 최고 전송자인 PayableContract에게 0.1 이더를 돌려줍니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d2987790-8fa9-41b3-a026-4f22a5c68b24&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-85463d79-54bf-49b1-92c8-61cadf96fb35&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기선 NonWithdrawalsContract의 richest, mostSent만 검사했지만 PayableContract의 이더리움 잔액도 검사해야 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9b439bc3-6e46-4d9b-a034-a4a6f1f600ba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-731a21c9-b3ac-4cd0-9f2d-bccc1cd1027d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(각 컨트랙트의 잔액 조회까지 들어가면 코드량이 너무 증가할 것 같아 PayableContract, NonPayableContract의 이더리움 잔액 조회 코드는 포함하지 않았습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4f74b883-0d56-44d2-b9cb-e09d4c372e51&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-b0ca477f-711e-4f62-96ce-fcb03bdc9929&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ PayableContract로 최고 전송자가 다시 바뀌는 상황&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-705158c2-ba19-433e-9515-b52068ec3f4e&quot;&gt;
&lt;pre id=&quot;code_1661640216817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;it('NonPayable -&amp;gt; Payable로 다시 바뀌는 경우: NonPayable에게 NonPayable.transfer 발생: 지금부터 NonWithdrawContract의 mostSent보다 높은 이더 전송시 에러', async function () {
  // 해당 케이스는 반드시 에러가 발생한다.
  // NonWithdrawalContract의 richest는 receive()가 구현되어 있지 않기 때문에 .transfer()가 정상동작 할 수 없다.
  // NonWithdrawalContract 해당 컨트랙트는 richest를 바꿀 수 있는 방법이 없기 때문에 더이상 동작하지 않는 코드가 된다.

  const to = NonWithdrawalContract.address;
  const amount = web3.utils.toWei('0.3', 'ether');
  const tx = this.payableContract.send(to, amount); 

  await truffleAssert.reverts(
    tx,
    'revert'
  );
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f0ebe983-5577-4ac1-8fc5-e229b259f654&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cd93b8e8-8242-4374-8c7b-48fd1e5ca8f0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최고 전송자가 바뀌면서 NonPayableContract에게 transfer()로 호출하기 때문에 에러가 발생합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f8be670c-cf5c-456c-a98f-996731394a5c&quot;&gt;
&lt;pre id=&quot;code_1661640221537&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  await truffleAssert.reverts(
    tx,
    'revert'
  );&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ab8bbb00-ae39-409e-af79-18eac2b237c7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-637d79aa-5cf3-4d5a-92ea-8b6aea943678&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;에러가 발생하는지 검사하는 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-41d9feb8-4f34-4d8b-ad98-1084b91bef3a&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 계속 에러 발생&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d76f5716-57e7-44ff-b4aa-c533af9ec680&quot;&gt;
&lt;pre id=&quot;code_1661640232817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;it('에러1', async function () {
    const to = NonWithdrawalContract.address;
    const amount = web3.utils.toWei('0.4', 'ether');
    const tx = this.payableContract.send(to, amount); 

    await truffleAssert.reverts(
      tx,
      'revert'
    );
  })
  
  it('에러2', async function () {

    const to = NonWithdrawalContract.address;
    const amount = web3.utils.toWei('0.4', 'ether');
    const tx = this.payableContract.send(to, amount); 

    await truffleAssert.reverts(
      tx,
      'revert'
    );
  })

  it('에러3', async function () {
    const to = NonWithdrawalContract.address;
    const amount = web3.utils.toWei('0.4', 'ether');
    const tx = this.nonPayableContract.send(to, amount); 

    await truffleAssert.reverts(
      tx,
      'revert'
    );
  })&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f6499a98-9296-4212-8f42-b3b6750c6afc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9c2c5898-b161-437e-a78f-160163208407&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이후 누가 이더를 전송하든 항상 에러가 발생합니다. 만약, NonWithdrawalsContract가 출금 패턴을 적용했다면 PayableContract가 호출하는 에러1, 에러2는 정상적으로 호출됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cb3a2d00-8139-4ed0-a7e3-906da67ad155&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e65db860-b343-486c-ac7c-2392719e0700&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;샘플 코드는 깃허브로 공유합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a86a1354-c68e-40c8-bd8c-222cc9b05e5d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6f318746-8e16-4287-893f-89b42edbc92a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/pjt3591oo/truffle-withdrawal-pattern&quot;&gt;https://github.com/pjt3591oo/truffle-withdrawal-pattern&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661640237897&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - pjt3591oo/truffle-withdrawal-pattern&quot; data-og-description=&quot;Contribute to pjt3591oo/truffle-withdrawal-pattern development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/pjt3591oo/truffle-withdrawal-pattern&quot; data-og-url=&quot;https://github.com/pjt3591oo/truffle-withdrawal-pattern&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jgMLl/hyPAzMcFKr/lVMqAWHCtixnp4HW2wgwd1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/pjt3591oo/truffle-withdrawal-pattern&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/pjt3591oo/truffle-withdrawal-pattern&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jgMLl/hyPAzMcFKr/lVMqAWHCtixnp4HW2wgwd1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - pjt3591oo/truffle-withdrawal-pattern&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to pjt3591oo/truffle-withdrawal-pattern development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>블록체인</category>
      <category>patterns</category>
      <category>solidity</category>
      <category>truffle</category>
      <category>withdraw</category>
      <category>withdrawals</category>
      <category>솔리디티</category>
      <category>출금</category>
      <category>출금패턴</category>
      <category>트러플</category>
      <category>패턴</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/82</guid>
      <comments>https://meongae.tistory.com/82#entry82comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:44:30 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] truffle을 이용하여 스마트 컨트랙트 개발하기</title>
      <link>https://meongae.tistory.com/81</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;ruffle을 이용하여 스마트 컨트랙트를 개발하는 방법을 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id=&quot;SE-05d25d0e-eb1d-4027-b3e1-16916b752eee&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-e73a2c6e-3a97-4bd1-a12c-07cc07b9673f&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● &lt;/b&gt;&lt;b&gt;셋업&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8bc16531-1238-431e-a915-d305501bfa90&quot;&gt;
&lt;pre id=&quot;code_1661639092126&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install -g truffle&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-755b80dc-8a64-458e-a496-653831a78d59&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-b0aa428a-93a6-4942-adaf-f51f7af5d4a5&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 프로젝트 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ff77615f-e6db-4c60-a1ed-d84eb8116a84&quot;&gt;
&lt;pre id=&quot;code_1661639101380&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir dapp
$ cd dapp

$ truffle init&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7aaba780-7f4a-4813-aacd-cc24662820df&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b56ebf9e-4a23-41d6-9c08-9f9ef0ee20fd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;init 명령어를 사용하여 truffle 기반의 프로젝트를 생성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-003a9797-3bc6-446f-a864-9c39d2f7a637&quot;&gt;
&lt;pre id=&quot;code_1661639108614&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ tree
.
├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
└── truffle-config.js

3 directories, 3 files&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6f54ed8f-a725-444d-a464-3104a9ce39fe&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-99be38c3-29ab-4a2a-a859-784c409aa2f6&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶ contracts&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4d418cbb-9568-4a4b-8d5c-50f19382cb7b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;solidity 코드 관리&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4bd29faa-097e-4041-a977-49da41657df7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fa73043f-c10f-43fe-a1ec-22f3c27b9364&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶ migrations&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e8edb9d0-5692-4130-89cd-89f53e7b59a1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스마트 컨트랙트 배포 관리&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7bc83f53-0a1c-4fc9-b60d-e96f9cb94b15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a63f79d4-eff4-47f5-87ae-fd3fa49fae6e&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶ test&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d9d4e3a5-abb1-4942-89ac-1f2771770c3f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;테스트 코드 작성&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7a6a7026-19ab-444e-9dd0-8ec0ae95cefe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8cc59406-47a9-47d8-8443-53d237c5817c&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶ build&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-15b6f857-81be-4331-b850-76f772e4af1d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;build는 컴파일 결과를 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-421bda30-8891-4d90-8cab-4a52ecaa1ad4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-de4d341d-5e06-4cca-a2c4-bb7f1013f888&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;프로젝트 생성시에는 없지만 compile을 하면 build/contracts 아래에 metadata.json를 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b8d831fd-2ff2-4da4-aad1-167621940a9e&quot;&gt;
&lt;pre id=&quot;code_1661639134398&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle compile&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9b915e8f-c3c3-4260-8b4c-1ac9088ca749&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4abd0dc7-1301-4a88-960f-7fed0e6ec5cd&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶truffle-config.js&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-95395002-ee97-4af6-841c-6289bea43aca&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크 연결정보 및 solidity compiler 버전 정보 등을 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8c6552ec-9a7c-4643-b9c8-6939a7bd9e7a&quot;&gt;
&lt;pre id=&quot;code_1661639160561&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * trufflesuite.com/docs/advanced/configuration
*/

// const HDWalletProvider = require('@truffle/hdwallet-provider');
// const fs = require('fs');
// const mnemonic = fs.readFileSync(&quot;.secret&quot;).toString().trim();

module.exports = {
  networks: {
    dev: {
     host: &quot;127.0.0.1&quot;,
     port: 8545,       
     network_id: &quot;*&quot;,
    },
  },
  mocha: {},
  compilers: {
    solc: {
      version: &quot;0.8.10&quot;,
    }
  },
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-55539f57-c4e6-4b1f-bf96-b6507a13243d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e93b936d-121e-49c3-9163-dcea8aa63ec5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;network는 더 많은 정보를 넣을 수 있습니다. 이외에 더 많은 정보를 설정할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e830573c-7a91-4137-977a-73aeec3b5091&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://trufflesuite.com/docs/truffle/reference/configuration&quot;&gt;https://trufflesuite.com/docs/truffle/reference/configuration&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661639181140&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Configuration - Truffle Suite&quot; data-og-description=&quot;Configuration Location Your configuration file is called truffle-config.js and is located at the root of your project directory. This file is a Javascript file and can execute any code necessary to create your configuration. It must export an object repres&quot; data-og-host=&quot;trufflesuite.com&quot; data-og-source-url=&quot;https://trufflesuite.com/docs/truffle/reference/configuration&quot; data-og-url=&quot;https://trufflesuite.com/docs/truffle/reference/configuration/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://trufflesuite.com/docs/truffle/reference/configuration&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://trufflesuite.com/docs/truffle/reference/configuration&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Configuration - Truffle Suite&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Configuration Location Your configuration file is called truffle-config.js and is located at the root of your project directory. This file is a Javascript file and can execute any code necessary to create your configuration. It must export an object repres&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;trufflesuite.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e0dff073-5f3f-467d-8a58-f9e494942477&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a6ab04ac-3eaf-4db6-9a08-6fbc05adc2a9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-b8520694-37aa-447a-9f89-d5f24a0b3f97&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 개발 프로세스&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-81e6f772-6ab5-45ed-bc6c-99f4e2c7e9a8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일반적으로 개발이라하면 다음과 같은 프로세스에 맞춰서 개발합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c295c809-e167-4397-ab24-9165e4ca49c8&quot;&gt;
&lt;pre id=&quot;code_1661639189207&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 소스코드 작성

2. 컴파일 &amp;amp; 빌드

3. 배포

4. 개별적으로 실행해보기

5. 테스트 하기&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2968e8bb-fea6-4765-8195-02e655777bd3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-76ce1212-c45a-4341-9dae-8696f5c8d0dd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;truffle은 이런 일련의 과정을 코드 및 명령어 기반으로 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-476a4c5b-e0cc-4843-a189-e31bfd5b6fbc&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 소스코드 작성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-52db75e3-d4bd-44e5-a8f1-a31776fded33&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;소스코드는 contracts 아래에서 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-19e40297-6efa-4abb-8e63-934e88bcd40f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;파일명: &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;contracts/Mung.sol&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-de8671cb-490b-4301-9eea-0f10121e583d&quot;&gt;
&lt;pre id=&quot;code_1661639208423&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED 
pragma solidity ^0.8.9; 

contract Mung {
    string public text; 

    constructor(string memory _text) { 
        text = _text;
    }
    
    function setText(string memory _text) public{
        text = _text;
    }

    function errorOccur(uint a) public pure returns (uint) {
        require(a != 0, &quot;hello world error&quot;);
        return a;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-da52f52b-3a28-4353-8b20-15b319a11abe&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-1def14ba-7822-430a-8e7d-7f12cc169e56&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 컴파일 및 빌드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f20a11c2-5ae1-4830-95e0-58e0cb5f3cf0&quot;&gt;
&lt;pre id=&quot;code_1661639228865&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle compile

Compiling your contracts...
===========================
&amp;gt; Compiling ./contracts/HelloWorld.sol
&amp;gt; Compiling ./contracts/Migrations.sol
&amp;gt; Compiling ./contracts/Mung.sol
&amp;gt; Artifacts written to /Users/jeongtaepark/Desktop/ethereum-truffle-sample/build/contracts
&amp;gt; Compiled successfully using:
   - solc: 0.8.10+commit.fc410830.Emscripten.clang&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-82584dc1-447d-47c2-a7f2-7d6086dfb6f1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-db2ca6ca-510d-4064-b6e4-812739a2e0fc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;빌드를 성공적으로 완료하면 build/contracts/*.json를 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d62ac413-03e7-42ca-9cee-14ffd33275f8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-f86677f7-6a66-4e40-9823-0ea9a4f8dff1&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 스마트컨트랙트 배포&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-deab47b8-8d72-4bc7-917b-fde31cd6de0b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;truffle은 migrate 명령어만으로 아주 쉽게 배포를 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cc918b2e-47ab-405a-9a4c-5f9f133db9b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-21b37406-dc9f-4dc6-a372-7645853cff02&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배포에 대한 코드는 migrations 아래에서 관리합니다. 이 코드는 생성자 전달할 인자를 정의합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-87a23c90-81fc-410f-aea5-b255f3932d9f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6f8c597b-043e-47ff-a562-43725865a8e9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;파일명: &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;migrations/2_Mung.js&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ebef9561-d0ee-44f7-978b-c8c9ea008ce5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c876de33-c33b-4b26-874c-3a8512dd330b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 한가지 중요한 점은 migrations는 다른 디렉터리와 다르게 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&quot;숫자_&quot;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;를 prefix해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ba7d7e74-e48b-482f-9935-fff3339d574f&quot;&gt;
&lt;pre id=&quot;code_1661639245376&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Mung = artifacts.require(&quot;Mung&quot;);

module.exports = function (deployer) {
  deployer.deploy(Mung, &quot;Hello Mung~&quot;);
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e34b558c-ea09-4d2d-966a-fb1068cade70&quot;&gt;
&lt;pre id=&quot;code_1661639253120&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle migrate --network [truffle-config에 명시한 network]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-103e4153-ae18-4f39-9e08-b0733143c2cd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-126f871d-6bd0-49f2-ab77-0f6cbe066210&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기선 dev로 노드 정보를 작성했기 때문에 --network dev를 전달합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7aff4371-5e26-4aab-aae0-6c896eda00b1&quot;&gt;
&lt;pre id=&quot;code_1661639265634&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle migrate --network dev&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-64615f8f-fa9c-4c8c-bc32-a4c137c46367&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661639271713&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Compiling your contracts...
===========================
&amp;gt; Everything is up to date, there is nothing to compile.

&amp;gt; Something went wrong while attempting to connect to the network at http://127.0.0.1:8545. Check your network configuration.

Could not connect to your Ethereum client with the following parameters:
    - host       &amp;gt; 127.0.0.1
    - port       &amp;gt; 8545
    - network_id &amp;gt; *
Please check that your Ethereum client:
    - is running
    - is accepting RPC connections (i.e., &quot;--rpc&quot; or &quot;--http&quot; option is used in geth)
    - is accessible over the network
    - is properly configured in your Truffle configuration file (truffle-config.js)

Truffle v5.4.22 (core: 5.4.22)
Node v14.17.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-787509d7-6962-4899-88f8-d93bdb8e775c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4afe94c6-1779-413f-acd8-6819aeb3c388&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;앗! 에러가!!!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5d55c4da-8858-4364-b4a6-005d63260818&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-896847e4-6f66-440f-aa9b-5015b1061e76&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;할 시간에 에러를 읽으세요 제발좀...&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4eb20f14-6236-429c-aafa-3606e83157b7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b41d7846-ad54-437e-aedf-bcdecaa9ba41&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 에러는 dev로 정의한 노드를 연결할 수 없다는 에러입니다. 당연히 연결을 못하죠. 노드가 로컬에 없으니&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-249fa6a0-bb08-42f3-b97f-dd380b8b5c3c&quot;&gt;
&lt;pre id=&quot;code_1661639278570&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install -g ganache-cli
$ ganache-cli&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b971fa7b-f113-4082-b0f8-4768324c0c6d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-99fc7fdf-cd42-40bc-8e9d-a2c7f02a3181&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;ganache-cli를 이용하여 가상의 네트워크를 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bdfbf798-a4f9-4f92-a78c-124150775c9f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3e742425-17e4-4120-bf26-962a63503316&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다시 migrate하면 정상적으로 스마트 컨트랙트를 배포할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661639294851&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Compiling your contracts...
===========================
&amp;gt; Everything is up to date, there is nothing to compile.

Starting migrations...
======================
&amp;gt; Network name:    'dev'
&amp;gt; Network id:      1637999164665
&amp;gt; Block gas limit: 6721975 (0x6691b7)

2_Mung.js
=========

   Deploying 'Mung'
   ----------------
   &amp;gt; transaction hash:    0xb390ac6cc6cfe4b52220d0388e5b595fd1b79696de1ed1ced5b6fe373a6347ab
   &amp;gt; Blocks: 0            Seconds: 0
   &amp;gt; contract address:    0x680d78685dE52F50201bC4e5b1723Daf44Bc6449
   &amp;gt; block number:        5
   &amp;gt; block timestamp:     1637999206
   &amp;gt; account:             0x19258f77721790dB2cEBe89fdBE1f241BCA95202
   &amp;gt; balance:             99.97578014
   &amp;gt; gas used:            425863 (0x67f87)
   &amp;gt; gas price:           20 gwei
   &amp;gt; value sent:          0 ETH
   &amp;gt; total cost:          0.00851726 ETH


   &amp;gt; Saving migration to chain.
   &amp;gt; Saving artifacts
   -------------------------------------
   &amp;gt; Total cost:          0.00851726 ETH


Summary
=======
&amp;gt; Total deployments:   3
&amp;gt; Final cost:          0.02281934 ETH&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e5b5be2f-47d1-42c2-a0c4-687e23c3a610&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f56a3e65-c1d2-441f-ae1b-e1c2ad11d28e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-881ec579-d14a-4ddf-a843-5d6a06ad1764&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 실행&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-6558cee8-a21e-4085-b7f3-acb4ab5003ba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;실행은 해당 컨트랙트의 함수 및 변수를 콘솔모드에서 호출할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f63cf48f-48d2-4876-81f8-2adaab60da6d&quot;&gt;
&lt;pre id=&quot;code_1661639307778&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle console --network dev
truffle(dev)&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cdd154b2-72be-49fe-8541-9cedd209af94&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9b60ad2f-f9b2-4932-8387-8c5d2034d1c6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;truffle(network)&amp;gt;는 콘솔모드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-36cc4489-1830-495f-8ef6-953656ffa99e&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ 배포한 컨트랙트 가져오기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-46b442ac-2e65-4040-9dca-aae9466e667b&quot;&gt;
&lt;pre id=&quot;code_1661639322755&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;truffle(dev)&amp;gt; contract = await Mung.deployed()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fd083622-f043-428f-a916-a6367bd3cb11&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-179ec826-a6fe-484b-b14c-a9a8f5fc0239&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ text 변수 값 가져오기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2430f03d-a907-4659-9544-6a5f0b3168bf&quot;&gt;
&lt;pre id=&quot;code_1661639336755&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;truffle(dev)&amp;gt; contract.text.call()
'Hello Mung~'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0a73f15c-cd17-4213-ab5e-8f8900955da2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-8df9af14-0898-4e30-989c-184e47e93947&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ setText() 함수 호출&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-504639ef-3af1-468d-9f0b-faff1c697af5&quot;&gt;
&lt;pre id=&quot;code_1661639346876&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;truffle(dev)&amp;gt; contract.setText( 'mung', { from: accounts[0] } )
{
  tx: '0x06e58ff5e6c6f3dd45d433549a0c0a299d88dea3d621c8f6b1ec5bc44984f8d2',
  receipt: {
    transactionHash: '0x06e58ff5e6c6f3dd45d433549a0c0a299d88dea3d621c8f6b1ec5bc44984f8d2',
    transactionIndex: 0,
    blockHash: '0x8bd35ce4b109100374e15f3bfe70995fa0e2f9a2ff534ec69fbc1b05e6c1ed15',
    blockNumber: 7,
    from: '0x19258f77721790db2cebe89fdbe1f241bca95202',
    to: '0x680d78685de52f50201bc4e5b1723daf44bc6449',
    gasUsed: 29574,
    cumulativeGasUsed: 29574,
    contractAddress: null,
    logs: [],
    status: true,
    logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    rawLogs: []
  },
  logs: []
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fb9bbac8-c959-4f40-a8d2-04e5c6beee0c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f381baf3-53f8-4ed2-9c5d-3da8331c4443&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;setText()는 트랜잭션을 발생하기 위해 마지막 인자로 트랜잭션을 발생할 주소를 전달합니다. 만약 {from: accounts[0]}이 없다면 기본으로 accounts[0]가 트랜잭션을 만듭니다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-290bd577-86e3-4409-8454-7a0f4f7dc4e3&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ text 변수 값 가져오기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ddc47d4f-2206-43a3-9623-4dae7bb3a4c0&quot;&gt;
&lt;pre id=&quot;code_1661639364652&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;truffle(dev)&amp;gt; contract.text.call()
'mung'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-94c9637e-3b37-452f-a0e4-9fe65925b73f&quot;&gt;
&lt;pre id=&quot;code_1661639368883&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;truffle(dev)&amp;gt; contract.text()
'mung'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-48effd3b-4d02-4ff8-af0a-338d1e54aee4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cf1932ea-ec09-4514-b2d5-1068eabdebf2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;원하는 스타일로 작성합니다. 개인적으로 call()을 호출해서 사용하는 방법을 선호합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;SE-501039ff-a898-4683-834e-db8a771d6773&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ error를 일으키는 함수 정상 호출&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b80fc268-59ee-4cb1-ae1e-2157a1cc3464&quot;&gt;
&lt;pre id=&quot;code_1661639379724&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;truffle(dev)&amp;gt; contract.errorOccur(1, { from: accounts[0]})
BN { negative: 0, words: [ 1, &amp;lt;1 empty item&amp;gt; ], length: 1, red: null }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3aeb8b9c-f385-451b-8c25-c4856c345f3b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 id=&quot;SE-bd43a7a6-8d4f-4f0e-a08c-4f1949bde2b0&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;▶ error를 일으키는 함수 정상 호출&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b7a1ae78-d133-41b6-a155-743dea66b90f&quot;&gt;
&lt;pre id=&quot;code_1661639384956&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;truffle(dev)&amp;gt; contract.errorOccur(0, { from: accounts[0]})
Uncaught:
Error: Returned error: VM Exception while processing transaction: revert hello world error&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7e50dad8-c233-4ba7-a41b-d40a7ee58b84&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-cafcf6f4-0eb0-4f46-ab4b-78a9fcde300a&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 테스트하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-1397d1ef-117b-4e87-84a6-35576ea6e089&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코드가 바뀔 때마다 앞의 과정을 반복적으로 한다면 아주 멍개같은 짓 입니다. 똑개는 절대 저렇게 테스트하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-058b23f6-fb38-4930-bf55-a1fac7f2af3e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;테스트 코드는 test 아래에서관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2f481e6d-b753-4233-a612-375e5a2e2d5b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0ef16e49-935e-4c1b-8478-8706eba86ba4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그 전에 라이브러리 하나를 설치하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9e3d9986-3944-46e8-a003-114b7a39b3f6&quot;&gt;
&lt;pre id=&quot;code_1661639395420&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save truffle-assertions&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bfabd1db-d6de-42c5-83b6-c83f097e0d7d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b289b769-6258-4c6d-af94-b44f620eefbf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;truffle-assertions은 revert가 발생하는 것을 테스트할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e17aeccd-62b6-42df-933b-6c6ed605ab40&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a27ddfaf-45b7-465e-916a-772aaafc9393&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;파일명: &lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;test/test_mung.js&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0afa1870-53f1-4511-8aab-61009b381685&quot;&gt;
&lt;pre id=&quot;code_1661639408831&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const truffleAssert = require('truffle-assertions');
const Mung = artifacts.require(&quot;Mung&quot;);

contract(&quot;Mung&quot;, accounts =&amp;gt; {
 // 각각의 테스트 케이스인 it을 실행할 때마다 before 실행하여 스마트 컨트랙트 객체를 가져옴
 before(async () =&amp;gt; {
   this.instance = await Mung.deployed();
 })

 it(&quot;should be initialized with correct value&quot;, async () =&amp;gt; {
   // 스마트 컨트랙트에 정의된 text() 함수 호출
   const text = await this.instance.text(); 
   assert.equal(text, &quot;Hello Mung~&quot;, &quot;Wrong initialized value!&quot;);
 });

 it(&quot;should change the text&quot;, async () =&amp;gt; {
   const changedText = 'hoho';
   // 스마트 컨트랙트에 정의된 setText() 함수 호출
   // 마지막 객체는 트랜잭션 발생 정보를 가진다.
   await this.instance.setText(changedText, {from: accounts[0]});
   // 스마트 컨트랙트에 정의된 say() 함수 호출
   const text = await this.instance.text();
   assert.equal(text, changedText, &quot;dose not change the value!&quot;);
 });

 it(&quot;should throw exception&quot;, async () =&amp;gt; {
   // 스마트 컨트랙트에 정의된 errorOccur() 함수 호출
   await truffleAssert.reverts(
     this.instance.errorOccur(0, {from: accounts[0]}),
     &quot;hello world error&quot;
   )
 });

 it(&quot;should not throw exception&quot;, async () =&amp;gt; {
   // 스마트 컨트랙트에 정의된 errorOccur() 함수 호출
   const rst = await this.instance.errorOccur(1, {from: accounts[0]});
   assert.equal(rst.words[0], 1, &quot;ErrorOccur event not emitted!&quot;);
 });
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7322cc77-9238-43d8-a679-38e3eda450d9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661639418237&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ truffle test --network dev
Using network 'dev'.


Compiling your contracts...
===========================
&amp;gt; Everything is up to date, there is nothing to compile.



  Contract: HelloWorld
    ✓ should be initialized with correct value
    ✓ should change the greeting (199ms)
    ✓ should throw exception (239ms)

  Contract: Mung
    ✓ should be initialized with correct value
    ✓ should change the text (190ms)
    ✓ should throw exception
    ✓ should not throw exception


  7 passing (838ms)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8446ff58-7a98-4df2-a1bc-fed725e97e98&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-60219d24-17a5-4bef-8938-ec9b59a0bcf5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기까지 진행했다면 다음과 같은 구조가 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1cbbb1a9-872f-43d3-81e4-e512407814b5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1661639425294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.
├── README.md
├── build
│   └── contracts
│       ├── Migrations.json
│       └── Mung.json
├── contracts
│   ├── Migrations.sol
│   └── Mung.sol
├── migrations
│   ├── 1_initial_migration.js
│   └── 2_Mung.js
├── package-lock.json
├── package.json
├── test
│   └── test_mung.js
└── truffle-config.js

5 directories, 11 files&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-28ce2ca8-da34-4a6c-be2f-93a3fcfcbd5d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0074cddf-733c-4471-ad6f-1333036016c4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-929d480e-4d3d-475b-b265-62d1798a2055&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 진행한 코드는 깃허브에서 확인 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dcc418f6-aec1-4fe1-9a61-30f479854685&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://github.com/pjt3591oo/ethereum-truffle-sample&quot;&gt;https://github.com/pjt3591oo/ethereum-truffle-sample&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661639436293&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - pjt3591oo/ethereum-truffle-sample&quot; data-og-description=&quot;Contribute to pjt3591oo/ethereum-truffle-sample development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/pjt3591oo/ethereum-truffle-sample&quot; data-og-url=&quot;https://github.com/pjt3591oo/ethereum-truffle-sample&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/S5jRO/hyPBMpB1Fm/nKMKTkMT95rPV6Swak1ix1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/pjt3591oo/ethereum-truffle-sample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/pjt3591oo/ethereum-truffle-sample&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/S5jRO/hyPBMpB1Fm/nKMKTkMT95rPV6Swak1ix1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - pjt3591oo/ethereum-truffle-sample&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to pjt3591oo/ethereum-truffle-sample development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9261e2bc-5d2e-11ec-8da4-9f231c1a3c35&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-92751cfd-5d2e-11ec-8da4-b7c2cf7b8ec4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>Ethereum</category>
      <category>Framework</category>
      <category>truffle</category>
      <category>스마트 컨트랙트</category>
      <category>트러픔</category>
      <category>프레임워크</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/81</guid>
      <comments>https://meongae.tistory.com/81#entry81comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:30:53 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] solidity overflow, underflow에 대해서</title>
      <link>https://meongae.tistory.com/80</link>
      <description>&lt;div id=&quot;SE-1173ebed-a1ab-4397-9bd6-d4ee0e59fb3c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-550F7863-95D3-4D73-A6A2-A8D91D2419D1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;solidity 8.x부터 overflow, underflow가 발생하는 연산은 revert가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6f3713b6-61ad-47d5-b8d1-c707fa71b1e9&quot;&gt;
&lt;pre id=&quot;code_1661639006178&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;

contract Test {
    function f(uint a, uint b) pure public returns(uint) {
        return a - b;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cc432851-90fc-465e-b110-bdada8334623&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1aDx8/btrKGxUuW8S/EYdQ6L2crTE5mEeZXHcTIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1aDx8/btrKGxUuW8S/EYdQ6L2crTE5mEeZXHcTIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1aDx8/btrKGxUuW8S/EYdQ6L2crTE5mEeZXHcTIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1aDx8%2FbtrKGxUuW8S%2FEYdQ6L2crTE5mEeZXHcTIk%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;773&quot; height=&quot;644&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-19e701ea-5722-434a-afb9-00aeedfbaafd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-65F83B88-A90D-442D-8CEE-92F3E398D90C&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;0에서 1을 감소하면 underflow가 발생하기 때문에 revert가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-CFC7E170-B64C-4C84-841F-7677F161D57E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2168649B-0588-4F3A-9F73-2259A49FAFA1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 의도적인 underflow를 발생해야 한다면 unchecked를 이용하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bbc90451-cb93-4683-8392-0ee01505f021&quot;&gt;
&lt;pre id=&quot;code_1661639014449&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;

contract Test {
    function g(uint a, uint b) pure public returns(uint) {
        unchecked { return a - b; }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e674a8e2-3b51-4016-a92b-144fc46db461&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnLiNb/btrKHefO0Xm/Q8Bca2KKEKeopBzs6crgkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnLiNb/btrKHefO0Xm/Q8Bca2KKEKeopBzs6crgkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnLiNb/btrKHefO0Xm/Q8Bca2KKEKeopBzs6crgkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnLiNb%2FbtrKHefO0Xm%2FQ8Bca2KKEKeopBzs6crgkK%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;773&quot; height=&quot;644&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-796bbf1d-4e40-4722-8b5d-18669ccf9196&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-569E9A7F-122A-4CD5-BFA2-46BC183EC72E&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>Ethereum</category>
      <category>overflow</category>
      <category>Remix</category>
      <category>solidity</category>
      <category>unchecked</category>
      <category>underflow</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/80</guid>
      <comments>https://meongae.tistory.com/80#entry80comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:23:50 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] input data의 methodId와 event signature 만드는 방법</title>
      <link>https://meongae.tistory.com/79</link>
      <description>&lt;div id=&quot;SE-6f7c4d61-4c76-473a-bd23-4146b7a16262&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-517ce7df-df16-4362-8226-83253f20c6b7&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● methodId&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-b4bdfb8b-f831-40fa-b5de-1c580cab9c51&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;etherscan을 보다보면 input Data가 다음과 같이 출력되는 모습을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d54667ea-7e58-4dd1-adbb-00c251ef5cbf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGyrJd/btrKHbDlvjF/vxfyebOlARtlxJxP0reUk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGyrJd/btrKHbDlvjF/vxfyebOlARtlxJxP0reUk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGyrJd/btrKHbDlvjF/vxfyebOlARtlxJxP0reUk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGyrJd%2FbtrKHbDlvjF%2FvxfyebOlARtlxJxP0reUk1%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;773&quot; height=&quot;107&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;107&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9ac1fe67-b056-4c78-8229-cd13879dd3e6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-aba4e805-fc8b-4ace-b417-211c248e5bd2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원래의 input data로 변환하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-de5df795-c2a8-4b59-b8dc-94960c6bb565&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;103&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IwLT8/btrKGOBATDe/Jk0UxgEL2Z0uk6F381tIpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IwLT8/btrKGOBATDe/Jk0UxgEL2Z0uk6F381tIpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IwLT8/btrKGOBATDe/Jk0UxgEL2Z0uk6F381tIpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIwLT8%2FbtrKGOBATDe%2FJk0UxgEL2Z0uk6F381tIpk%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;773&quot; height=&quot;103&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f3fc8b51-2fdd-4051-a62f-aaa8356b2601&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ca798f26-cd90-4d2b-b785-cfb906a4f6ba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 methodID는 어떤 원리로 만들어 지는지 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9862910e-cd6b-4144-9eca-9676f8ed4a77&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-968fa776-42bd-4c93-8bd4-2ebbc9f1b723&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; solidity&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-896b6a3b-ae06-4d4a-b184-90509d21ed6d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4c17731b-dc54-4963-b7ad-fc1c6aff14c0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUaetK/btrKMGBO2d0/YvvbdAGGUBSukJXkLvzUg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUaetK/btrKMGBO2d0/YvvbdAGGUBSukJXkLvzUg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUaetK/btrKMGBO2d0/YvvbdAGGUBSukJXkLvzUg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUaetK%2FbtrKMGBO2d0%2FYvvbdAGGUBSukJXkLvzUg0%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;592&quot; height=&quot;522&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;pre id=&quot;code_1661638719451&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contract Test {
    function setA() public pure returns (bytes memory) {
       // return bytes4(keccak256('balanceOf(address)')); 해당 방법도 가능
       return abi.encodeWithSignature(&quot;transfer(address,uint256)&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ea831e3a-8803-4776-afc1-1b29652810d3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-dd5ebabe-c78c-41e6-bb2f-9193b481caa1&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; web3&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d43be45e-3a67-48e9-8699-e10083768fea&quot;&gt;
&lt;pre id=&quot;code_1661638739498&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Web3 = require('web3');
const web3 = new Web3()

console.log(web3.eth.abi.encodeFunctionSignature(&quot;transfer(address,uint256)&quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-81eaed02-e372-4a31-9340-093cdd696917&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a900a782-a903-4ef2-a104-bc2d1f88c268&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661638743417&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;0xa9059cbb&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-6d113ee1-1a6f-46e7-9176-1cbcc6ce2e47&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;abi를 object 형태로 전달하는 방법도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9ec5bf1d-aff0-4ff1-927e-69f43557b3d6&quot;&gt;
&lt;pre id=&quot;code_1661638751961&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Web3 = require('web3');
const web3 = new Web3()

web3.eth.abi.encodeFunctionSignature({
  name: 'transfer',
  type: 'function',
  inputs: [{
      type: 'address',
      name: 'to'
  },{
      type: 'uint256',
      name: 'value'
  }]
})&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1661638756321&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;0xa9059cbb&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e1069a88-06f3-4101-8056-61210fb1618c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c0e78073-e3be-4e63-8101-ec3dd96a975e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-a1413bba-090b-4f7a-a879-1b8b66f6a058&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● event signature&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 id=&quot;SE-aa4f496e-90b3-4fa5-8c9d-db100725d18d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; web3js&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-95aadb93-2dc4-45cc-8fe2-6ff7afb09859&quot;&gt;
&lt;pre id=&quot;code_1661638771952&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;web3.eth.abi.encodeEventSignature(&quot;Transfer(address,address,uint256)&quot;)

web3.eth.abi.encodeEventSignature({
  name: 'Transfer',
  type: 'event',
  inputs: [{
    indexed: true,
    type: 'address',
    name: 'from'
  }, {
    indexed: true,
    type: 'address',
    name: 'to'
  },{
    type: 'uint256',
    name: 'value'
  }]
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-95cb3600-9b5f-4833-8e6d-e726bce42595&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b4034f57-c4b2-4699-b7cb-1a9cfa0e934a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661638777195&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-dcd5d25e-6af0-43c8-839f-6d345ceff311&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>Ethereum</category>
      <category>methodid</category>
      <category>Signature</category>
      <category>web3</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/79</guid>
      <comments>https://meongae.tistory.com/79#entry79comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:19:51 +0900</pubDate>
    </item>
    <item>
      <title>[solidity] library, enum</title>
      <link>https://meongae.tistory.com/78</link>
      <description>&lt;div id=&quot;SE-2461a355-d863-4637-aba3-ac0f5666f652&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-85cf3284-9824-4883-95fd-c0ac2f3721ea&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; library &lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-993bc470-0738-473e-b902-499165b41b2e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;library는 컨트랙트를 라이브러리처럼 사용할 수 있도록 도와줍니다. 다만 library를 사용하기 위해선 &lt;/span&gt;&lt;span&gt;&lt;b&gt;using ~ for ~&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 키워드를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dcae7600-bd05-4aaf-9fa9-bc97aad37a59&quot;&gt;
&lt;pre id=&quot;code_1661638562429&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity 0.8.9;

library MyLibrary {
    struct data {
        string name;  
        uint age;
    }
    
    function add(uint a, uint b) external pure returns (uint) {
        return a + b;
    }
}

library Math {
    function add (uint _a, uint _b) external pure returns (uint) {
        return _a + _b;
    }
    
    function sub (uint _a, uint _b) external pure returns (uint) {
        return _a - _b;
    }
}

contract MyContract {
    
    using MyLibrary for MyLibrary.data;
    using Math for *;

    MyLibrary.data charactor;

    function getA () public view returns (MyLibrary.data memory) {
        return charactor;
    }
    
    function setA (string memory _name, uint _age) public  {
        charactor = MyLibrary.data(_name, _age);
    }
    
    function mathAdd (uint _a, uint _b) public pure returns (uint) {
        return Math.add(_a, _b);
    }
    
    function mathSub (uint _a, uint _b) public pure returns (uint) {
        return Math.sub(_a, _b);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bfd11307-a8f3-4638-a61c-20c2e9338068&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-43a0917f-3a23-470b-a916-135451d3244c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 MyLibrary와 Math를 별도의 파일로 분리한다고 하면 import로 가져온 후 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8d036088-85bd-43c2-bc45-1cdd1c111840&quot;&gt;
&lt;pre id=&quot;code_1661638573316&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// library.sol
pragma solidity 0.8.9;

library MyLibrary {
    struct data {
        string name;  
        uint age;
    }
    
    function add(uint a, uint b) external pure returns (uint) {
        return a + b;
    }
}

library Math {
    function add (uint _a, uint _b) external pure returns (uint) {
        return _a + _b;
    }
    
    function sub (uint _a, uint _b) external pure returns (uint) {
        return _a - _b;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b2da4390-bb4c-41d4-a7ff-76e6a7714b56&quot;&gt;
&lt;pre id=&quot;code_1661638579926&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity 0.8.9;

import './library.sol';

contract MyContract {
    
    using MyLibrary for MyLibrary.data;
    using Math for *;

    MyLibrary.data charactor;

    
    function getA () public view returns (MyLibrary.data memory) {
        return charactor;
    }
    
    function setA (string memory _name, uint _age) public  {
        charactor = MyLibrary.data(_name, _age);
    }
    
    function mathAdd (uint _a, uint _b) public pure returns (uint) {
        return Math.add(_a, _b);
    }
    
    function mathSub (uint _a, uint _b) public pure returns (uint) {
        return Math.sub(_a, _b);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6eca8019-e14a-41c7-94a6-e7405671be40&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;661&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nEJUs/btrKJ6gKpUo/pHaI05bihHoE3skRd7VCa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nEJUs/btrKJ6gKpUo/pHaI05bihHoE3skRd7VCa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nEJUs/btrKJ6gKpUo/pHaI05bihHoE3skRd7VCa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnEJUs%2FbtrKJ6gKpUo%2FpHaI05bihHoE3skRd7VCa1%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;773&quot; height=&quot;661&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;661&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-31667d9e-e3a6-4f56-8f7b-7bfc8abfb381&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-c27a514d-aebf-4afc-b572-7077d4348d95&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; enum&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f2028f72-be24-4216-866b-e0e3352d87ce&quot;&gt;
&lt;pre id=&quot;code_1661638587091&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity 0.8.9;

contract MyContract {
    enum  bb { a1, a2, a3 }
    
    function getA() public pure returns (bb) {
        return bb.a1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-63fe55a0-a949-481b-83ed-3b6d93ae5b2e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-04c31b17-0b15-4187-b051-1a8dc64964f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;enum은 연속된 자연수를 특정 문자열에 맵핑하여 관리할 때 유용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e15ecc86-9c6e-48fe-8924-f23c5387b2c8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-923be274-3bc6-4ed8-a265-0895df7f3f4f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;enum은 상수를 변수로 관리하는데 의의가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>enum</category>
      <category>Ethereum</category>
      <category>library</category>
      <category>solidity</category>
      <category>솔리디티</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/78</guid>
      <comments>https://meongae.tistory.com/78#entry78comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:16:47 +0900</pubDate>
    </item>
    <item>
      <title>[solidity] 에러함수 -  require, revert, assert</title>
      <link>https://meongae.tistory.com/77</link>
      <description>&lt;div id=&quot;SE-760f5f16-f998-4115-a5f7-2c891afc8ace&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4520fb24-4f0f-4484-8d94-c4c6b628797e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;olidity는 require, revert, assert가 호출되면 에러를 발생하고 &lt;/span&gt;&lt;span style=&quot;color: #54b800;&quot;&gt;&lt;b&gt;rollback&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 수행합니다. &lt;/span&gt;&lt;span style=&quot;color: #54b800;&quot;&gt;&lt;b&gt;rollback&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이란 함수가 호출되기 전의 상태로 돌아가는 것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d3215484-264a-41ce-aee6-92b0fa6ad0f6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e5e3bfba-b6db-4262-b7cc-0795bb30887d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;롤백(rollback)은 데이터베이스 관점에서 매우 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-68cfb68e-65d9-4cd9-ac27-b628c6e04017&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; revert + error &lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f047f4b5-d2f8-4e8e-a9ca-99eb130ddacf&quot;&gt;
&lt;pre id=&quot;code_1661638414917&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.8.4;

error WowError(uint x, uint y);

contract SimpleStorage {
    uint public storedData;
 
    function set(uint x) public {
        if (x == 3){
            revert WowError(1, x);
        }
        storedData = x;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-20e50098-af70-422e-9184-3712cf76f7d4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a525acf3-b700-4eec-856f-b392b12c4586&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;revert()는 호출 됨과 동시에 에러를 발생시켜 rollback 처리합니다. 이때 error로 정의된 함수를 호출하여 커스텀 메시지를 만들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4f2c7acf-ed84-4916-b726-f0d0ba53900b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rm5WG/btrKIxsahjA/Hj2kh16SNdOBP2tXCcwZok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rm5WG/btrKIxsahjA/Hj2kh16SNdOBP2tXCcwZok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rm5WG/btrKIxsahjA/Hj2kh16SNdOBP2tXCcwZok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRm5WG%2FbtrKIxsahjA%2FHj2kh16SNdOBP2tXCcwZok%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;773&quot; height=&quot;551&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-968a1abf-f998-4149-9a08-77d2c49f21e2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-6ca4d125-1f0a-460b-83ad-e65fe6f86e41&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;solidity에서는 에러를 만드는 방법이 몇가지 있습니다. revert()를 호출하는 방법도 있지만 require을 이용하는 방법도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fe8c7ae1-7007-4489-86d5-a4bc45aaf492&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;revert 말고 require, assert도 존재합니다. revert는 require, assert 처럼 나온지는 한참되었습니다. 하지만 error 함수는 0.8.4 버전 이후에 등장했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ad58e412-6cc7-4fa9-8ab5-e9f0ae5ec788&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7c9742f7-87a2-414e-a41f-880040c8879e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;revert 함수만 다루면 require과 assert가 섭섭해할테니 간략하게 다뤄보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-925b1cd9-a2a6-4fd6-b78d-004256257e89&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;​&lt;b&gt;&amp;middot; require&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06b18c48-44f8-4d36-9488-773b4cfa9116&quot;&gt;
&lt;pre id=&quot;code_1661638438004&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.8.4;

contract SimpleStorage {
    uint storedData;
 
    function set(uint x) public {
        require(x != 3, &quot;x is not 3&quot;);
        storedData = x;
    }
 
    function get() view public returns (uint) {
        return storedData;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d1082b15-6ea2-42a7-8bd3-26d5ecb8d615&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-54a4ec52-bcd6-450a-9bef-6447808bc96c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;require은 첫 번째 인자로 boolean을 전달하고 두 번째 인자로 에러 메시지를 전달합니다. 첫 번째 인자가 false인 경우 에러를 발생시키고 두 번째 인자로 전달한 문자열을 알려줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ba89de9e-d6dc-4910-a7c1-d3265ae1f1f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;require()의 두 번째 인자는 옵셔널하기 때문에 꼭 전달하지 않아도 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9f266960-b568-4803-ac10-be20a7e9c2eb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;147&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCil4O/btrKJ53em2i/dpqGY4Ky2dH86kFdXuEJRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCil4O/btrKJ53em2i/dpqGY4Ky2dH86kFdXuEJRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCil4O/btrKJ53em2i/dpqGY4Ky2dH86kFdXuEJRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCil4O%2FbtrKJ53em2i%2FdpqGY4Ky2dH86kFdXuEJRK%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;773&quot; height=&quot;147&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;147&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5f3082bd-e2df-4b46-9c58-b280cebee049&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-435d961e-3422-4bfb-9093-118245ca39b2&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; assert&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4234f34e-f13d-4eac-a31a-dcf1ab01892d&quot;&gt;
&lt;pre id=&quot;code_1661638452347&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.8.4;

contract SimpleStorage {
    uint storedData;
 
    function set(uint x) public {
     
        storedData = x;
        
        assert(storedData != 3);
    }
 
    function get() view public returns (uint) {
        return storedData;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-413869b2-346f-4135-a1e3-e5ca465bab5a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O8zG3/btrKHuij0vE/PHATcyVhNJvb6XFCDRZqU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O8zG3/btrKHuij0vE/PHATcyVhNJvb6XFCDRZqU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O8zG3/btrKHuij0vE/PHATcyVhNJvb6XFCDRZqU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO8zG3%2FbtrKHuij0vE%2FPHATcyVhNJvb6XFCDRZqU1%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;773&quot; height=&quot;136&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3cbeb772-a146-4804-885b-898f3b029107&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d5dfa901-50b3-49ae-8ae8-fd67c99f5de0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bb4f9d13-405d-42ee-b836-ed72ea528d8c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661638468334&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;require: 소유권 검사
revert: 데이터 유효성 검사 및 사전검사(예: 정상적으로 데이터가 들어왔는지, 계산에 필요한 만큼 값을 가지고 있는지)
assert: 연산 후 유효성 검사(예: overflow, underflow 검사)&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-bb647e96-45ca-4cde-b0fb-21d4075ba950&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 assert의 검사를 빼먹는 경우가 종종 있는데 assert를 이용해서 반드시 overflow와 underflow 처리를 해야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-26d61e52-7676-4110-9164-fb0301020bb2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e0e4e512-18cd-4eaa-8af3-a61e1589cfc7&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;※ overflow와 underflow&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cf19e958-787c-42d2-9f51-9f5d82889e58&quot;&gt;
&lt;pre id=&quot;code_1661638478169&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.7.4;

contract SimpleStorage {
    uint min = 0;
    uint max = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
    function under() public view returns( uint) {
        return min - 1;
    }
    
    function over() public view returns( uint) {
        return max + 1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-81cc5796-41c1-44e1-beaa-0f59672410e6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUjETr/btrKLgXGTKR/S0V0PnpcuA37CWYBton7nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUjETr/btrKLgXGTKR/S0V0PnpcuA37CWYBton7nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUjETr/btrKLgXGTKR/S0V0PnpcuA37CWYBton7nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUjETr%2FbtrKLgXGTKR%2FS0V0PnpcuA37CWYBton7nK%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;298&quot; height=&quot;242&quot; data-origin-width=&quot;298&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9cbb771b-63f3-49c4-a19a-4b3b3ceb9b34&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-94d6c488-377e-45f9-b42d-15c9434fcd7c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;over 함수는 연산 결과는 최댓값에서 + 1을 하여 다시 0으로 돌아옵니다. 이를 &lt;/span&gt;&lt;span&gt;&lt;b&gt;오버플로우(overflow)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;라고 부릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-008536f9-acab-483e-bd73-8898dd8d9d18&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;under 함수는 최소값인 0에서 - 1을 하여 최대값이 됩니다. 이를 &lt;/span&gt;&lt;span&gt;&lt;b&gt;언더플로우(underflow)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e48452e3-e5dc-441b-818c-94eea97d89e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b08c3fca-098b-45f3-b0ce-00e3b106dcc3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;assert는 overflow, underflow 뿐 아니라 연산 결과가 정확히 나왔는지 검사하는것이 매우 중요하며 앞의 예시는 solidity 0.8.x 이후에선 발생하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b3aa00be-2b5a-42b9-9ca8-eb42c04126b7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bb9de725-3ba3-4578-9674-d853a9170b27&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;pragma solidity를 통해 다른 버전을 명시한 후 remix에서 컴파일러 버전을 바꿔주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3a29c538-6448-4e39-b4a3-891864c936de&quot;&gt;
&lt;pre id=&quot;code_1661638485089&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.8.4;

contract SimpleStorage {
    uint min = 0;
    uint max = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
    function under() public view returns( uint) {
        return min - 1;
    }
    
    function over() public view returns( uint) {
        return max + 1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b84b75d7-3d75-4d64-b9da-a75fa2d98285&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4kN9L/btrKGQGgLW2/UREdXSRRm0wJSZTLHGeZM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4kN9L/btrKGQGgLW2/UREdXSRRm0wJSZTLHGeZM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4kN9L/btrKGQGgLW2/UREdXSRRm0wJSZTLHGeZM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4kN9L%2FbtrKGQGgLW2%2FUREdXSRRm0wJSZTLHGeZM1%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;773&quot; height=&quot;335&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;335&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-35e6c41c-6097-489c-b17d-472ac70ca7fc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c5848b67-3e79-4717-a64b-80caf522ec37&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;값에서 overflow, underflow가 일어나면 내부적으로 revert를 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>assert</category>
      <category>overflow</category>
      <category>require</category>
      <category>revert</category>
      <category>solidity</category>
      <category>underflow</category>
      <category>솔리디티</category>
      <category>언더플로우</category>
      <category>오버플로우</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/77</guid>
      <comments>https://meongae.tistory.com/77#entry77comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:15:03 +0900</pubDate>
    </item>
    <item>
      <title>[Ethereum] genesis 초기화 시 cannot unmarshal 에러 해결법</title>
      <link>https://meongae.tistory.com/76</link>
      <description>&lt;div id=&quot;SE-100ea6be-7810-4261-a472-f3a032c70bdf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cd9b7899-4654-473c-a91b-ecf55d5358d1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;안녕하세요 멍개입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-73a9a52b-c944-4b93-9d14-9815e4c04444&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-03ba9358-f704-4093-8cc2-0f5e436f8320&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;geth를 이용하여 네트워크 구축 시 genesis 파일을 만들게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b11668fc-8897-49f4-a6b0-67f176b625c9&quot;&gt;
&lt;pre id=&quot;code_1661638283375&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;config&quot;: {
    &quot;chainId&quot;: 1234,
    &quot;homesteadBlock&quot;: 0,
    &quot;eip150Block&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
    &quot;eip155Block&quot;: 0,
    &quot;eip158Block&quot;: 0,
    &quot;byzantiumBlock&quot;: 0,
    &quot;constantinopleBlock&quot;: 0,
    &quot;petersburgBlock&quot;: 0,
    &quot;istanbulBlock&quot;: 0,
    &quot;berlinBlock&quot;: 0,
    &quot;londonBlock&quot;: 0,
    &quot;ethash&quot;: {}
  },
  &quot;alloc&quot;: {
    &quot;56aE1237F0D3E2F21683Bd04402092E26f469813&quot;:{&quot;balance&quot;:&quot;30000000000000000000000&quot;},  
    &quot;55e2d8BF452e1E7D70eb375B527fd38B281B00cF&quot;:{&quot;balance&quot;:&quot;30000000000000000000000&quot; }
  },
  &quot;coinbase&quot;: &quot;0x56aE1237F0D3E2F21683Bd04402092E26f469813&quot;,
  &quot;difficulty&quot;: &quot;0x20000&quot;,
  &quot;extraData&quot;: &quot;&quot;,
  &quot;gasLimit&quot;: &quot;0x2fefd8&quot;,
  &quot;nonce&quot;: &quot;0x0000000000000042&quot;,
  &quot;mixhash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;parentHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;timestamp&quot;: &quot;0x00&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-52bf0f8e-467e-428b-bef7-20eba60f0ee4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-36574199-26e8-42ff-96e9-40f805b03dff&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 내용으로 genesis.json으로 만들었다면 다음과 같이 genesis 초기화를 시킬 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661638302396&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir $PWD init genesis.json
Fatal: invalid genesis file: math/big: cannot unmarshal &quot;\&quot;0000000000000000000000000000000000000000000000000000000000000000\&quot;&quot; into a *big.Int&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5fea2125-9db4-4541-9ede-05c0c76069e0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;11&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/24yyh/btrKMogTHl9/cB5S27fy2sdcosD3nmbed1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/24yyh/btrKMogTHl9/cB5S27fy2sdcosD3nmbed1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/24yyh/btrKMogTHl9/cB5S27fy2sdcosD3nmbed1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F24yyh%2FbtrKMogTHl9%2FcB5S27fy2sdcosD3nmbed1%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;773&quot; height=&quot;11&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;11&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4f32d7d5-5218-45ee-853f-e30e1615c586&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-74e0d49b-fb5f-4f7a-81f4-6ff34374e722&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 에러는 0x000000이 Int 타입이 아니라 발생하는 에러입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-57203442-2048-431a-8b07-34bc25a4acb1&quot;&gt;
&lt;pre id=&quot;code_1661638317404&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;config&quot;: {
    &quot;chainId&quot;: 1234,
    &quot;homesteadBlock&quot;: 0,
    &quot;eip150Block&quot;: 0,
    &quot;eip155Block&quot;: 0,
    &quot;eip158Block&quot;: 0,
    &quot;byzantiumBlock&quot;: 0,
    &quot;constantinopleBlock&quot;: 0,
    &quot;petersburgBlock&quot;: 0,
    &quot;istanbulBlock&quot;: 0,
    &quot;ethash&quot;: {}
  },
  &quot;alloc&quot;: {
    &quot;56aE1237F0D3E2F21683Bd04402092E26f469813&quot;:{&quot;balance&quot;:&quot;30000000000000000000000&quot;},  
    &quot;55e2d8BF452e1E7D70eb375B527fd38B281B00cF&quot;:{&quot;balance&quot;:&quot;30000000000000000000000&quot; }
  },
  &quot;coinbase&quot;: &quot;0x56aE1237F0D3E2F21683Bd04402092E26f469813&quot;,
  &quot;difficulty&quot;: &quot;0x20000&quot;,
  &quot;extraData&quot;: &quot;&quot;,
  &quot;gasLimit&quot;: &quot;0x2fefd8&quot;,
  &quot;nonce&quot;: &quot;0x0000000000000042&quot;,
  &quot;mixhash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;parentHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;timestamp&quot;: &quot;0x00&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ac22393f-a51c-461c-afce-e9cddecf086e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;99&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKbobf/btrKGo4eNYM/q8tMwuCtRll2qE2Jfy1K10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKbobf/btrKGo4eNYM/q8tMwuCtRll2qE2Jfy1K10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKbobf/btrKGo4eNYM/q8tMwuCtRll2qE2Jfy1K10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKbobf%2FbtrKGo4eNYM%2Fq8tMwuCtRll2qE2Jfy1K10%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;773&quot; height=&quot;99&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;99&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-641abf09-a908-464c-8fc7-0d5646850f11&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f0176d17-ab75-49eb-99e1-ac224b93c8a7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정상적으로 초기화되는 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>Ethereum</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/76</guid>
      <comments>https://meongae.tistory.com/76#entry76comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:12:23 +0900</pubDate>
    </item>
    <item>
      <title>[Ethereum] EIP1559 네워크축 구축을 위한 제네시스 설정방법</title>
      <link>https://meongae.tistory.com/75</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;geth를 이용하여 노드를 구축할 때 EIP1559 사용가능한 형태로 노드를 띄우는 방법을 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b06bbbd6-779d-4b68-afb1-dc3b927ee44f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;본론으로 들어가기 앞서서 EIP1559 방식이 무엇인지 궁금하다면 다음 링크에서 EIP1559가 무엇인지 간략하게 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/74&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.28 - [블록체인] - [Ethereum] EIP1559 GETH, Ganache-cli 사용해보기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661638037102&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Ethereum] EIP1559 GETH, Ganache-cli 사용해보기&quot; data-og-description=&quot;현재 이더리움은 EIP1559 적용이 되었습니다. ​ EIP1559 적용 후 트랜잭션 발생시 gas 사용방법이 바뀌었습니다. ​ ▶ before(Legacy) { from, to, gas: 25000, gasPrice: '21000000000', value: '1000000000000..&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/74&quot; data-og-url=&quot;https://meongae.tistory.com/74&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/k0Q1d/hyPBUVtRWp/wsbaxrkCOPSKKuKa1kQ9v0/img.png?width=773&amp;amp;height=90&amp;amp;face=0_0_773_90,https://scrap.kakaocdn.net/dn/tolbO/hyPAwIGKel/NjZRINHdDreb6qZNNh3uX1/img.png?width=773&amp;amp;height=90&amp;amp;face=0_0_773_90,https://scrap.kakaocdn.net/dn/bb3u1v/hyPAyfrN3Z/0c8ofvaCrJtjBOO8wKJqyK/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/74&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/74&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/k0Q1d/hyPBUVtRWp/wsbaxrkCOPSKKuKa1kQ9v0/img.png?width=773&amp;amp;height=90&amp;amp;face=0_0_773_90,https://scrap.kakaocdn.net/dn/tolbO/hyPAwIGKel/NjZRINHdDreb6qZNNh3uX1/img.png?width=773&amp;amp;height=90&amp;amp;face=0_0_773_90,https://scrap.kakaocdn.net/dn/bb3u1v/hyPAyfrN3Z/0c8ofvaCrJtjBOO8wKJqyK/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Ethereum] EIP1559 GETH, Ganache-cli 사용해보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;현재 이더리움은 EIP1559 적용이 되었습니다. ​ EIP1559 적용 후 트랜잭션 발생시 gas 사용방법이 바뀌었습니다. ​ ▶ before(Legacy) { from, to, gas: 25000, gasPrice: '21000000000', value: '1000000000000..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;div id=&quot;SE-0b325ab9-bed4-4d80-b509-efd8d2cfeabc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-00bb3e72-650a-4ea3-9db0-c5bf49019165&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;EIP1559 방식을 사용하기 위해선 geth 프로그램 1.10.8 버전이후여야 합니다. 사실 앞의 블로그를 작성할 땐 geth 1.10.7 버전이었는데 해당 버전의 깃허브 README에서 genesis 정보를 제대로 알려주지 않아 EIP1559 방식의 트랜잭션을 발생할 수 없었습니다. 물론 README가 정리되어 있지 않더라도 코드&lt;/span&gt;&lt;span&gt;&lt;b&gt;(parmas/config.go)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에서 어떤 설정값들을 넣어줘야 하는지 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0a2fc312-af4f-478c-bb4b-589481c68e8f&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IH1p9/btrKHtX02kd/xzqhSPky4Wfk2wJPlUWdKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IH1p9/btrKHtX02kd/xzqhSPky4Wfk2wJPlUWdKK/img.png&quot; data-alt=&quot;버전: 1.10.7&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IH1p9/btrKHtX02kd/xzqhSPky4Wfk2wJPlUWdKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIH1p9%2FbtrKHtX02kd%2FxzqhSPky4Wfk2wJPlUWdKK%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;773&quot; height=&quot;578&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;버전: 1.10.7&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-104c7025-b3a9-45b0-84da-966d19b28f50&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-477d81a4-6132-4d0b-9362-ad094f7e991c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 최신버전을 확인하면 다음과 같이 config에 londonBlock이 추가된 모습을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4b947d17-fbf9-442a-b861-cf141c44ea92&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0QFP2/btrKGx1ar2o/wCkKyik0Q4GdBLcGAn9hr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0QFP2/btrKGx1ar2o/wCkKyik0Q4GdBLcGAn9hr0/img.png&quot; data-alt=&quot;버전: 1.10.8&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0QFP2/btrKGx1ar2o/wCkKyik0Q4GdBLcGAn9hr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0QFP2%2FbtrKGx1ar2o%2FwCkKyik0Q4GdBLcGAn9hr0%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;773&quot; height=&quot;578&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;버전: 1.10.8&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cc73f748-689e-4139-b1ca-5096e6eaa083&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ec2fd989-52df-4ba1-b4de-c8d8595bb190&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;londonBlock이 있어야 EIP1559 방식으로 트랜잭션을 발생할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1661638052966&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;config&quot;: {
    &quot;chainId&quot;: &quot;임의의 값&quot;,
    &quot;homesteadBlock&quot;: 0,
    &quot;eip150Block&quot;: 0,
    &quot;eip155Block&quot;: 0,
    &quot;eip158Block&quot;: 0,
    &quot;byzantiumBlock&quot;: 0,
    &quot;constantinopleBlock&quot;: 0,
    &quot;petersburgBlock&quot;: 0,
    &quot;istanbulBlock&quot;: 0,
    &quot;berlinBlock&quot;: 0,
    &quot;londonBlock&quot;: 0
  },
  &quot;alloc&quot;: {},
  &quot;coinbase&quot;: &quot;0x0000000000000000000000000000000000000000&quot;,
  &quot;difficulty&quot;: &quot;0x20000&quot;,
  &quot;extraData&quot;: &quot;&quot;,
  &quot;gasLimit&quot;: &quot;0x2fefd8&quot;,
  &quot;nonce&quot;: &quot;0x0000000000000042&quot;,
  &quot;mixhash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;parentHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;timestamp&quot;: &quot;0x00&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;네트워크 구축 하는 방법은 기존에 방법과 동일하므로 다음 링크를 참고해주세요&lt;/span&gt;&lt;/p&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;a href=&quot;https://meongae.tistory.com/67&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.27 - [블록체인] - [ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661638087560&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&quot; data-og-description=&quot;Geth를 이용하여 Ethash(POW) 기반 private network 구축하는 방법을 알아보겠습니다. ​ Geth는 POW(Ethash), POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다. ​ 여기선 개념적인 내용보다 방법론적인..&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/67&quot; data-og-url=&quot;https://meongae.tistory.com/67&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bHDHF2/hyPBVfMdsB/udEHwcvnSQK4Ti7S6opkf1/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/jiwWb/hyPAC3cqeF/DHl3e7CMkZaDzJXMW7AiN0/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/gm4QA/hyPBNB2KFM/z0QQJr7CikXsz4Z6Clu54K/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/67&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/67&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bHDHF2/hyPBVfMdsB/udEHwcvnSQK4Ti7S6opkf1/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/jiwWb/hyPAC3cqeF/DHl3e7CMkZaDzJXMW7AiN0/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/gm4QA/hyPBNB2KFM/z0QQJr7CikXsz4Z6Clu54K/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Geth를 이용하여 Ethash(POW) 기반 private network 구축하는 방법을 알아보겠습니다. ​ Geth는 POW(Ethash), POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다. ​ 여기선 개념적인 내용보다 방법론적인..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 트랜잭션 발생&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-0f38476b-200d-4693-a46d-6d9d267c9efa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션 발생할 때 기존 방식(&lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;Legacy&lt;/b&gt;&lt;/span&gt;&lt;span&gt;)은 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;gas&lt;/b&gt;&lt;/span&gt;&lt;span&gt;와 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;gasPrice&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 전달합니다. &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;EIP1559&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 gasPrice 대신 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;maxFeePerGas&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;maxPriorityFeePerGas&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 전달합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a5867e42-896f-4489-b81a-9db0391d2f11&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;SE-46bc5755-6100-4628-b6af-a07da175fb5c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-848eab97-e7d8-4273-a808-c3ec7dfd830c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Legacy&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-30f39380-9812-4b4e-8f33-4652ab26df7f&quot;&gt;
&lt;pre id=&quot;code_1661638119897&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.sendTransaction({
    from: eth.accounts[0],
    to: eth.accounts[1],
    gas: 25000,
    gasPrice: '21000000000',
    value: '10000000'
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c5eab1a3-ca17-4458-8524-1001a0e0ffdc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-514ac7d2-2c77-4cb1-9838-b180f33e0db4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; EIP1559&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-438dc8ee-6020-4ea9-b8b1-cb49cc34bc8e&quot;&gt;
&lt;pre id=&quot;code_1661638131481&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;eth.sendTransaction({
    from: eth.accounts[0],
    to: eth.accounts[1],
    gas: 25000,
    maxFeePerGas: &quot;0xb2d05e00&quot;,         // 3000000000 = 3Gwei
    maxPriorityFeePerGas: &quot;0xb2d05e00&quot;, // 3000000000 = 3Gwei
    value: '10000000'
})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b10d791c-294c-4892-8595-9605d00ad6f0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SSLd7/btrKGPgclTS/NK37sBpyQZ8P0KKpQcJrv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SSLd7/btrKGPgclTS/NK37sBpyQZ8P0KKpQcJrv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SSLd7/btrKGPgclTS/NK37sBpyQZ8P0KKpQcJrv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSSLd7%2FbtrKGPgclTS%2FNK37sBpyQZ8P0KKpQcJrv0%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;773&quot; height=&quot;217&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d174e20a-1919-4ef9-907a-64c9d3adfbfa&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-c98c2ff2-42d1-4068-b02a-2e94c79ec927&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;​&lt;/b&gt;&lt;b&gt;● 트랜잭션 조회&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-0ad4e839-d540-48ff-a3e9-6ff1ff8f94e3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션을 조회하면 type으로 Legacy, EIP1559 트랜잭션을 구분할 수 있습니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-e24132c4-6e7c-4336-93fb-5b93301ebaff&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Legacy&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ce0bd404-00ed-4a05-922c-fe954bfad3e6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xGDN3/btrKMEYizeF/A0TU3QuvEr0x2juMAGSKd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xGDN3/btrKMEYizeF/A0TU3QuvEr0x2juMAGSKd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xGDN3/btrKMEYizeF/A0TU3QuvEr0x2juMAGSKd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxGDN3%2FbtrKMEYizeF%2FA0TU3QuvEr0x2juMAGSKd0%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;731&quot; height=&quot;309&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2ad98428-cb5f-4afd-8435-eea020a1fd88&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-25ec41d5-d475-44b0-90d3-fc7c27f649e6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; EIP1559&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-06cc5770-735b-412a-b521-e84aa3a4ead3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7BzHR/btrKHZPWRBB/rD6WSNQIZTvaLjqoWVDknk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7BzHR/btrKHZPWRBB/rD6WSNQIZTvaLjqoWVDknk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7BzHR/btrKHZPWRBB/rD6WSNQIZTvaLjqoWVDknk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7BzHR%2FbtrKHZPWRBB%2FrD6WSNQIZTvaLjqoWVDknk%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;734&quot; height=&quot;377&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0523d5fe-faca-4b0e-abb3-9d1eb0ceeafb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-262945c8-d782-4274-a53b-3ce44038301e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;EIP1559도 gasPrice가 존재합니다. Legacy와 다르게 사용자가 지정하지 않고 프로토콜 레벨에서 결정됩니다. 마치 블록 생성시 difficulty가 블럭생성 주기를 결정하기 위해 증가/감소 되는 것 처럼 특정 알고리즘에 의해 결정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-e5d8eb22-d2f2-4b47-9fd5-fb9c1fa16373&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● genesis config 확인&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-07bc74ae-7cd0-40d5-b49d-5db52fbaf049&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추가적으로 각 네트워크 별 genesis설정은 깃허브에서 확인가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e7ffa0af-de4b-4c3b-a046-a53c54df154a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/ethereum/go-ethereum/blob/master/params/config.go&quot;&gt;https://github.com/ethereum/go-ethereum/blob/master/params/config.go&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661638171324&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ethereum/go-ethereum: Official Go implementation of the Ethereum protocol&quot; data-og-description=&quot;Official Go implementation of the Ethereum protocol - GitHub - ethereum/go-ethereum: Official Go implementation of the Ethereum protocol&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ethereum/go-ethereum/blob/master/params/config.go&quot; data-og-url=&quot;https://github.com/ethereum/go-ethereum&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bxni9n/hyPBI1OBs8/tckEn4HwVzOcsKRYgpBBFK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ethereum/go-ethereum/blob/master/params/config.go&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ethereum/go-ethereum/blob/master/params/config.go&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bxni9n/hyPBI1OBs8/tckEn4HwVzOcsKRYgpBBFK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ethereum/go-ethereum: Official Go implementation of the Ethereum protocol&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Official Go implementation of the Ethereum protocol - GitHub - ethereum/go-ethereum: Official Go implementation of the Ethereum protocol&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bd6dbb97-f0a7-4bfc-b127-fa745e36605d&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9NwpS/btrKMEKLUiq/CmI02emcrfI9b6OxTsYDW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9NwpS/btrKMEKLUiq/CmI02emcrfI9b6OxTsYDW0/img.png&quot; data-alt=&quot;main network&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9NwpS/btrKMEKLUiq/CmI02emcrfI9b6OxTsYDW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9NwpS%2FbtrKMEKLUiq%2FCmI02emcrfI9b6OxTsYDW0%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;773&quot; height=&quot;334&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;main network&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c46b52d1-f197-4c48-b9e2-749e5689a67d&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWONpR/btrKHUHPgLr/yFIk8sruJByG4SXx2cQla1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWONpR/btrKHUHPgLr/yFIk8sruJByG4SXx2cQla1/img.png&quot; data-alt=&quot;ropsten network&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWONpR/btrKHUHPgLr/yFIk8sruJByG4SXx2cQla1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWONpR%2FbtrKHUHPgLr%2FyFIk8sruJByG4SXx2cQla1%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;773&quot; height=&quot;328&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ropsten network&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c403db8d-3815-4f5b-a538-d2b36ee0e5e1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b9d2ec1b-15c0-498e-9afc-3ae131b6600b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Ethash&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 POW로 동작하는 네트워크 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fd097d71-2912-45ae-a4ba-1a67216c2bb0&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F4qkp/btrKMo821yS/M5S2A8lvZh3RC0g1XhdopK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F4qkp/btrKMo821yS/M5S2A8lvZh3RC0g1XhdopK/img.png&quot; data-alt=&quot;rinkeyby network&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F4qkp/btrKMo821yS/M5S2A8lvZh3RC0g1XhdopK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF4qkp%2FbtrKMo821yS%2FM5S2A8lvZh3RC0g1XhdopK%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;773&quot; height=&quot;386&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;rinkeyby network&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d759f9d8-465c-4f50-a7df-20a44be05330&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;398&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhJu1S/btrKGp29lci/HNqdWWrJ38XploQErCsR10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhJu1S/btrKGp29lci/HNqdWWrJ38XploQErCsR10/img.png&quot; data-alt=&quot;goerli network&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhJu1S/btrKGp29lci/HNqdWWrJ38XploQErCsR10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhJu1S%2FbtrKGp29lci%2FHNqdWWrJ38XploQErCsR10%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;398&quot; height=&quot;413&quot; data-origin-width=&quot;398&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;goerli network&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a6753552-344d-44c3-b556-44d2f4c54f88&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-313a4cee-0625-485c-b3d4-20a771fc9885&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Clique는 POA로 동작하는 네트워크입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>eip1559</category>
      <category>Ethereum</category>
      <category>geth</category>
      <category>iondon</category>
      <category>transaction</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <category>트랜잭션</category>
      <category>하드포크</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/75</guid>
      <comments>https://meongae.tistory.com/75#entry75comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:10:24 +0900</pubDate>
    </item>
    <item>
      <title>[Ethereum] EIP1559 GETH, Ganache-cli 사용해보기</title>
      <link>https://meongae.tistory.com/74</link>
      <description>&lt;div id=&quot;SE-f26baf46-551d-48f5-a671-4e1bb5dbe4be&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2e0fbf4e-a89a-416d-a548-4a397cd04b36&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재 이더리움은 EIP1559 적용이 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1fc30a01-7163-41de-8387-d257fefb059f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-86aad750-87a8-4bbe-97e5-f7195067ad71&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;EIP1559 적용 후 트랜잭션 발생시 gas 사용방법이 바뀌었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8d447e26-f4b0-425e-9e7f-34790e0d5a53&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-37ffa82c-3340-4f6e-87d4-400f4e79095f&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶ before(Legacy)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-066c9e68-d5a7-4f07-a1b1-255d1d5f1800&quot;&gt;
&lt;pre id=&quot;code_1661637900184&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    from,
    to,
    gas: 25000,
    gasPrice: '21000000000',
    value: '1000000000000000'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5680d613-8ef9-4ecc-8049-93bbb2f63dee&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7f285323-b01d-4874-8760-84409488bac7&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶ after(EIP1559)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-76a5dc73-7a07-4ec1-9015-31b121d818e1&quot;&gt;
&lt;pre id=&quot;code_1661637906281&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    from,
    to,
    gas: 25000,
    maxFeePerGas: &quot;0xb2d05e00&quot;,         // 3000000000 = 3Gwei
    maxPriorityFeePerGas: &quot;0xb2d05e00&quot;, // 3000000000 = 3Gwei
    value: '1000000000000000'
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-321dc3d6-ba44-4209-9c66-081ab1b353c6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-969fa1c1-43ee-4447-83f8-145d6c3e8191&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존의 gasPrice가 maxFeePerGas와 maxProorityFeePerGas로 나뉘어졌습니다. gasPrice는 이제 노드 프로토콜 레이어에서 결정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1fcc6fd1-5ce2-4755-90f6-cbafe85068db&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-61e44495-a61f-4c4e-a7a5-5376a7d28f6e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;maxFeePerGass는 사용자가 최대 사용할 가스를 지정합니다. 만약 가스 사용이 이를 초과할 경우 트랜잭션은 취소되며, 초과하지 않으면 남은만큼 트랜잭션 발생 대상자에게 돌려줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1d2d128e-6c3e-4d8a-be2a-1cec8c2a3241&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4d495c74-38b0-4a05-a568-1fe4b0a3905c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;maxPriorityFeePerGas는 트랜잭션을 블록에 포함시킨 마이너 계정에게 보상할 수수료 입니다. 기존 방식에선 수수료 모두를 마이너가 가져갔지만 EIP1559에선 maxPriorityFeePerGas만큼만 마이너가 가져갑니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ab853041-d1e2-48d9-85b9-8ef0ce8fc3d8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-ea029640-73a8-4d9d-b5bc-bbd42632b4b6&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 노드 프로그램에서 지원여부&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-d2f0f936-421e-49c9-874c-d6e7a5c81fae&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움 노드 프로그램으로 &lt;/span&gt;&lt;span&gt;&lt;b&gt;geth,&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;ganache-cli&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-400de465-4917-4baa-8a8d-37becdf6531b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; geth&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7374589c-96fa-4cd6-bf26-f6a1fe2817e8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;90&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wu5Zg/btrKMEYis6c/mJSHMCJQiODwXD6MBsg5Wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wu5Zg/btrKMEYis6c/mJSHMCJQiODwXD6MBsg5Wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wu5Zg/btrKMEYis6c/mJSHMCJQiODwXD6MBsg5Wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwu5Zg%2FbtrKMEYis6c%2FmJSHMCJQiODwXD6MBsg5Wk%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;773&quot; height=&quot;90&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;90&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b12f67ec-c7af-4a83-994e-c6a00c8637fa&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-397b01d8-b325-46e1-8039-02a280775db7&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; ganache-cli&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6e2a5ee9-e76e-4556-93fa-21956854baf1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;91&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsY4lF/btrKIq0NvyV/ha8sk56gZKp4YyRPjIVikk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsY4lF/btrKIq0NvyV/ha8sk56gZKp4YyRPjIVikk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsY4lF/btrKIq0NvyV/ha8sk56gZKp4YyRPjIVikk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsY4lF%2FbtrKIq0NvyV%2Fha8sk56gZKp4YyRPjIVikk%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;773&quot; height=&quot;91&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;91&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-34d58457-db4b-4e9e-8824-4b6d82c2d333&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5a1ce8c1-294f-4386-98c7-fc95cc75322b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 프로그램 모두 EIP1559 방식의 트랜잭션 발생이 안됩니다. 아무래도 노드 설정이 필요한 것 같은데 기본적으로 지원을 하고있지 않은 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7fec79f7-c6b4-4b28-9fd1-ab7e1bc5d1c7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-24c39cbe-6933-4cd5-8b6d-863c5ee6a4d7&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● EIP1559 트랜잭션 VS Legacy 트랜잭션&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-34485124-cd66-453a-ac23-c2f3aa7776b6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;EIP1559 트랜잭션과 Legacy 트랜잭션은 타입으로 구분할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4f84c31b-b5f9-4de5-8612-c2acfab0a80b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;EIP1559&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #e57523;&quot;&gt;0x02&lt;/span&gt; Legacy &lt;span style=&quot;color: #a77f71;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #e57523;&quot;&gt;0x00&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ff4b0605-e3bb-416e-a781-6926f270628c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-80547eaf-5450-48ae-a169-1978aceff9e6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; EIP1559 트랜잭션&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b0b5a78c-0dc1-479a-89c8-554de18bb222&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;697&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YpKsj/btrKHUOB2e1/3PANqnUKedqiFkKWAo2Ry0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YpKsj/btrKHUOB2e1/3PANqnUKedqiFkKWAo2Ry0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YpKsj/btrKHUOB2e1/3PANqnUKedqiFkKWAo2Ry0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYpKsj%2FbtrKHUOB2e1%2F3PANqnUKedqiFkKWAo2Ry0%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;686&quot; height=&quot;697&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;697&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cc17b6f9-1841-475b-b049-e307fcb58650&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-81da029a-880d-4262-8354-8007241f3818&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-0474358e-b9c4-48c6-b434-39386f374f0f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Legacy 트랜잭션&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d146a51d-029f-42a3-8b36-4260459ee5f1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmtcrZ/btrKK8SUNdx/glVF3H4JX17ckheHb9TqP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmtcrZ/btrKK8SUNdx/glVF3H4JX17ckheHb9TqP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmtcrZ/btrKK8SUNdx/glVF3H4JX17ckheHb9TqP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmtcrZ%2FbtrKK8SUNdx%2FglVF3H4JX17ckheHb9TqP0%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;773&quot; height=&quot;516&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b02517d1-2a87-4883-967b-fa425e316f28&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a404abd3-6e85-4e6a-aa13-bd51604e2df6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;geth, ganache-cli 모두 지원이 안되는데 어찌 트랜잭션이 발생되는가..... 하면 다음 사이트에서 키를 발급받은 후 해당 노드를 이용하면 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://infura.io/&quot;&gt;https://infura.io/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661637964264&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Ethereum API | IPFS API &amp;amp; Gateway | ETH Nodes as a Service&quot; data-og-description=&quot;Infura's development suite provides instant, scalable API access to the Ethereum and IPFS networks. Connect your app to Ethereum and IPFS now, for free!&quot; data-og-host=&quot;infura.io&quot; data-og-source-url=&quot;https://infura.io/&quot; data-og-url=&quot;https://infura.io&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jX5w1/hyPAyNhwSh/hsFN7VSzLSM7vw6X2VF3L0/img.png?width=800&amp;amp;height=375&amp;amp;face=0_0_800_375&quot;&gt;&lt;a href=&quot;https://infura.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://infura.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jX5w1/hyPAyNhwSh/hsFN7VSzLSM7vw6X2VF3L0/img.png?width=800&amp;amp;height=375&amp;amp;face=0_0_800_375');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Ethereum API | IPFS API &amp;amp; Gateway | ETH Nodes as a Service&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Infura's development suite provides instant, scalable API access to the Ethereum and IPFS networks. Connect your app to Ethereum and IPFS now, for free!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;infura.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>블록체인</category>
      <category>EIP</category>
      <category>Ethereum</category>
      <category>ganache</category>
      <category>geth</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/74</guid>
      <comments>https://meongae.tistory.com/74#entry74comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:06:13 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] ERC721을 이용한 NFT 만들기 - 3편</title>
      <link>https://meongae.tistory.com/73</link>
      <description>&lt;span&gt; NFT 생성기 &lt;/span&gt;
&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://serviceapi.nmv.naver.com/flash/convertIframeTag.nhn?vid=C6A1DCF894D04966FAA8A740BCC488BF66BF&amp;outKey=V125882d022fd1fff457d2aafa2f2400c1bfaedc62bc0557dc3c92aafa2f2400c1bfa&quot; frameborder=&quot;no&quot; scrolling=&quot;no&quot; title=&quot;NaverVideo&quot; allow=&quot;autoplay; gyroscope; accelerometer; encrypted-media&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;span&gt; NFT 등록 로딩중&lt;/span&gt;
&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://serviceapi.nmv.naver.com/flash/convertIframeTag.nhn?vid=90106C7E9AE15714202B4FD3C8791B70D46A&amp;outKey=V1249960354b630de8071994d9e29bba102c3ecf805ff6a0accaa994d9e29bba102c3&quot; frameborder=&quot;no&quot; scrolling=&quot;no&quot; title=&quot;NaverVideo&quot; allow=&quot;autoplay; gyroscope; accelerometer; encrypted-media&quot; allowfullscreen&gt;&lt;/iframe&gt;

&lt;span&gt; 모바일 &lt;/span&gt;
&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://serviceapi.nmv.naver.com/flash/convertIframeTag.nhn?vid=2EB08BB28D291B9494FA47945B1B83116667&amp;outKey=V129ace75fe404fb11d6b8fb067d859944e6ed1220a11004cd8858fb067d859944e6e&quot; frameborder=&quot;no&quot; scrolling=&quot;no&quot; title=&quot;NaverVideo&quot; allow=&quot;autoplay; gyroscope; accelerometer; encrypted-media&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;▶ ropsten 네트워크 배포&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ropsten.etherscan.io/token/0x4fAb976447Abfab5ba35C94e298865409a9ddc6c&quot;&gt;https://ropsten.etherscan.io/token/0x4fAb976447Abfab5ba35C94e298865409a9ddc6c&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661637599682&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;() Token Tracker | Etherscan&quot; data-og-description=&quot;() Token Tracker on Etherscan shows the price of the Token $0.00, total supply 0, number of holders 1 and updated information of the token. The token tracker page also shows the analytics and historical data.&quot; data-og-host=&quot;ropsten.etherscan.io&quot; data-og-source-url=&quot;https://ropsten.etherscan.io/token/0x4fAb976447Abfab5ba35C94e298865409a9ddc6c&quot; data-og-url=&quot;https://ropsten.etherscan.io/token/0x4fAb976447Abfab5ba35C94e298865409a9ddc6c&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c6EHe4/hyPACvnKfG/6SkFEV8s6UNQKqI2Sieei1/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256,https://scrap.kakaocdn.net/dn/daWEnQ/hyPAt6gXU0/jC0aAGmOw3sixBBRGkAaQk/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256,https://scrap.kakaocdn.net/dn/vEetP/hyPBWy0oSN/SJIYdPTGFz6hepzXL8uyNK/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256&quot;&gt;&lt;a href=&quot;https://ropsten.etherscan.io/token/0x4fAb976447Abfab5ba35C94e298865409a9ddc6c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ropsten.etherscan.io/token/0x4fAb976447Abfab5ba35C94e298865409a9ddc6c&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c6EHe4/hyPACvnKfG/6SkFEV8s6UNQKqI2Sieei1/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256,https://scrap.kakaocdn.net/dn/daWEnQ/hyPAt6gXU0/jC0aAGmOw3sixBBRGkAaQk/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256,https://scrap.kakaocdn.net/dn/vEetP/hyPBWy0oSN/SJIYdPTGFz6hepzXL8uyNK/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;() Token Tracker | Etherscan&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;() Token Tracker on Etherscan shows the price of the Token $0.00, total supply 0, number of holders 1 and updated information of the token. The token tracker page also shows the analytics and historical data.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ropsten.etherscan.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;▶ ropsten 네트워크 배포 - NFT 생성기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;/u&gt;&lt;u&gt;&lt;a href=&quot;https://inspiring-newton-bf922b.netlify.app&quot;&gt;https://inspiring-newton-bf922b.netlify.app&lt;/a&gt;&lt;/u&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661637630595&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;NFT Generator&quot; data-og-description=&quot;&quot; data-og-host=&quot;inspiring-newton-bf922b.netlify.app&quot; data-og-source-url=&quot;https://inspiring-newton-bf922b.netlify.app/&quot; data-og-url=&quot;https://inspiring-newton-bf922b.netlify.app/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://inspiring-newton-bf922b.netlify.app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inspiring-newton-bf922b.netlify.app/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;NFT Generator&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inspiring-newton-bf922b.netlify.app&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;iframe width=&quot;1280&quot; height=&quot;720&quot; src=&quot;https://serviceapi.nmv.naver.com/flash/convertIframeTag.nhn?vid=1E94D4EF4525B29C20AD198B8C5F07A0D6FB&amp;outKey=V127362d830500ba4ef12094d0787416655bf0328b789c71af0c3094d0787416655bf&quot; frameborder=&quot;no&quot; scrolling=&quot;no&quot; title=&quot;NaverVideo&quot; allow=&quot;autoplay; gyroscope; accelerometer; encrypted-media&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;▶  solidity 0.5에서 0.8.9로 컨버팅&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ERC721의 인터페이스가 아닌 mint 함수를 추상 컨트랙트를 통해 인터페이스를 제공하여 명확한 형태의 코드로 개선하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7ea7f7f1-ee5d-45da-9a91-2f7c86c5c2d9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b5486c57-f7a3-4587-a642-3767122ca4ce&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/Exchange-M/NFT-ERC721&quot;&gt;https://github.com/Exchange-M/NFT-ERC721&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661638913400&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Exchange-M/NFT-ERC721: ERC721 for NFT&quot; data-og-description=&quot;ERC721 for NFT. Contribute to Exchange-M/NFT-ERC721 development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Exchange-M/NFT-ERC721&quot; data-og-url=&quot;https://github.com/Exchange-M/NFT-ERC721&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bmFSm2/hyPBVfMlLU/5lJRDBV025fBMlZ5MzegPk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/Exchange-M/NFT-ERC721&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Exchange-M/NFT-ERC721&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bmFSm2/hyPBVfMlLU/5lJRDBV025fBMlZ5MzegPk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - Exchange-M/NFT-ERC721: ERC721 for NFT&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;ERC721 for NFT. Contribute to Exchange-M/NFT-ERC721 development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1661638921175&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import 'https://github.com/Exchange-M/NFT-ERC721/blob/master/ERC721.sol';

contract Minty_ERC721 is Minty, ERC721 {
    // Counters.Counter 타입인 _ownedTokensCount[uint]가 library Counters에 정의된 increment(), decrement(), current()를 호출하기 위해 필요
    using Counters for Counters.Counter;
    
    function _mint(address to, uint256 tokenId) internal override {
        require(to != address(0), &quot;ERC721: mint to the zero address&quot;);
        require(!_exists(tokenId), &quot;ERC721: token already minted&quot;);

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();

        emit Transfer(address(0), to, tokenId);
    }
}

contract CharactorByERC721 is Minty_ERC721 {
    struct Charactor {
        string  name;  // 캐릭터 이름
        uint256 level; // 캐릭터 레벨
    }

    Charactor[] public charactors; // default: [] 
    address public owner;          // 컨트랙트 소유자

    constructor () {
        owner = msg.sender; 
    }

    modifier isOwner() {
      require(owner == msg.sender);
      _;
    }

    // 캐릭터 생성
    function mint(string memory name, address account) public isOwner {
        uint256 cardId = charactors.length; // 유일한 캐릭터 ID
        charactors.push(Charactor(name, 1));
        _mint(account, cardId); // ERC721 소유권 등록
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>blockchain</category>
      <category>erc</category>
      <category>erc721</category>
      <category>NFT</category>
      <category>블록체인</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/73</guid>
      <comments>https://meongae.tistory.com/73#entry73comment</comments>
      <pubDate>Sun, 28 Aug 2022 07:02:35 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] ERC721을 이용한 NFT 만들기 - 2편</title>
      <link>https://meongae.tistory.com/72</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;지난 시간에 우리는 NFT의 기본 개념과 ERC721을 이용하여 구현해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.28 - [블록체인] - [ethereum] ERC721을 이용한 NFT 만들기 - 1편&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661637286288&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[ethereum] ERC721을 이용한 NFT 만들기 - 1편&quot; data-og-description=&quot;ERC721 기반의 NFT를 만들어 본 후 가볍게 실습을 진행해보는 시간을 가져보도록 하겠습니다. ​ &amp;middot; NFT란? 최소한 NFT가 무엇인지부터 살펴보자. NFT는 대체 불가능한 토큰을 의미합니다. 여기서 대체&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/71&quot; data-og-url=&quot;https://meongae.tistory.com/71&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/CgdAr/hyPAC3cwHJ/nnM358dQ0Z9ABgKNqTDvUK/img.png?width=773&amp;amp;height=295&amp;amp;face=0_0_773_295,https://scrap.kakaocdn.net/dn/zWqs4/hyPAn51RYK/smslZRs3PqyzSK9VPQR9jk/img.png?width=773&amp;amp;height=295&amp;amp;face=0_0_773_295,https://scrap.kakaocdn.net/dn/c9jGIp/hyPACWqf5B/RSGXkmIALqPxUfVdR3sTqK/img.png?width=773&amp;amp;height=691&amp;amp;face=0_253_192_445&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/71&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/CgdAr/hyPAC3cwHJ/nnM358dQ0Z9ABgKNqTDvUK/img.png?width=773&amp;amp;height=295&amp;amp;face=0_0_773_295,https://scrap.kakaocdn.net/dn/zWqs4/hyPAn51RYK/smslZRs3PqyzSK9VPQR9jk/img.png?width=773&amp;amp;height=295&amp;amp;face=0_0_773_295,https://scrap.kakaocdn.net/dn/c9jGIp/hyPACWqf5B/RSGXkmIALqPxUfVdR3sTqK/img.png?width=773&amp;amp;height=691&amp;amp;face=0_253_192_445');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[ethereum] ERC721을 이용한 NFT 만들기 - 1편&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;ERC721 기반의 NFT를 만들어 본 후 가볍게 실습을 진행해보는 시간을 가져보도록 하겠습니다. ​ &amp;middot; NFT란? 최소한 NFT가 무엇인지부터 살펴보자. NFT는 대체 불가능한 토큰을 의미합니다. 여기서 대체&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;div id=&quot;SE-1dddcfee-91c6-4ca0-9e3a-a8b2a96d97f9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4bcc685f-afe6-4d40-a13c-c7918f510e37&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1편에서 작성한 코드를 추상화하여 좀 더 클린한 형태로 발전시켜 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9169f9dc-1b60-4b35-a3b6-ba0cc6e04917&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9a1a805c-8f53-453d-9bbd-374a1afa4843&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 구현한 실제 비즈니스 로직이 포함된 코드는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a227992a-4688-40e3-b0ad-10e0aa959f70&quot;&gt;
&lt;pre id=&quot;code_1661637329818&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contract CharactorByERC721 is ERC721{
    struct Charactor {
        string  name;  // 캐릭터 이름
        uint256 level; // 캐릭터 레벨
    }

    Charactor[] public charactors; // default: [] 
    address public owner;          // 컨트랙트 소유자

    constructor () public {
        owner = msg.sender; 
    }

    modifier isOwner() {
      require(owner == msg.sender);
      _;
    }

    // 캐릭터 생성
    function mint(string memory name, address account) public isOwner {
        uint256 cardId = charactors.length; // 유일한 캐릭터 ID
        charactors.push(Charactor(name, 1));
        _mint(account, cardId); // ERC721 소유권 등록
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a8c51eff-5bc1-4f51-bbbd-185cee19d9ba&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1f31ae2d-1a58-4821-888d-750add5012cb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그렇다면, 우리는 이외의 코드는 굳이 직접 작성할 필요는 없습니다. 하지만 울리가 앞서서 ERC721 컨트랙트 인터페이스로 제공하지 않는 _mint()를 추가하였는데 이를 확장하고 우리가 개발에 집중할 수 있는 형태로 제공해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eb31bf7f-67d8-4a8e-914b-652a1f2e3608&quot;&gt;
&lt;pre id=&quot;code_1661637337029&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function _mint(address to, uint256 tokenId) internal {
    require(to != address(0), &quot;ERC721: mint to the zero address&quot;);
    require(!_exists(tokenId), &quot;ERC721: token already minted&quot;);
    _tokenOwner[tokenId] = to;
    _ownedTokensCount[to].increment();
    emit Transfer(address(0), to, tokenId);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c1574579-ef99-48cb-bb6c-2e64b67544c0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-017470f5-3807-427f-8286-7b4b83f93f2d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자 먼저 _mint에서 접근하는 녀석들을 알아보아야 합니다. _tokenOwner, _ownedTokensCount, _exists를 접근하고 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1285688d-8f55-4004-9ca8-dc15e6d144fa&quot;&gt;
&lt;pre id=&quot;code_1661637344114&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 토큰 ID에서 소유자로의 매핑
mapping (uint256 =&amp;gt; address) private _tokenOwner;

// 토큰 ID에서 승인된 주소로의 매핑
mapping (uint256 =&amp;gt; address) private _tokenApprovals;

function _exists(uint256 tokenId) internal view returns (bool) {
    address owner = _tokenOwner[tokenId];
    return owner != address(0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6c3d1ea2-fb05-4ab0-843d-23cc9662a9d8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-87bd79e0-4836-487c-8a40-b31b9d6be8ed&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 상속받은 컨트랙트에서 접근할 수 있도로 접근자를 수정합니다. 접근자는 &lt;/span&gt;&lt;span&gt;&lt;b&gt;private&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에서 &lt;/span&gt;&lt;span&gt;&lt;b&gt;interval&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 바꿔줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d7972e22-7001-47d6-a6de-aea1915ec00e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-55bab043-bc87-4fd7-9876-311fb131f878&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661637351016&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 토큰 ID에서 소유자로의 매핑
mapping (uint256 =&amp;gt; address) interval _tokenOwner;

// 토큰 ID에서 승인된 주소로의 매핑
mapping (uint256 =&amp;gt; address) internal _tokenApprovals;

function _exists(uint256 tokenId) internal view returns (bool) {
    address owner = _tokenOwner[tokenId];
    return owner != address(0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;SE-521f4fdb-b34a-48bb-9a3a-30b23657878e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 수정된 ERC721 컨트랙트 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-075a5cf8-acdf-4c77-832d-f2f07746ef0a&quot;&gt;
&lt;pre id=&quot;code_1661637365993&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contract ERC721 is ERC165, IERC721 {
    using SafeMath for uint256;
    using Address for address;
    using Counters for Counters.Counter;

    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    mapping (uint256 =&amp;gt; address) internal _tokenOwner;

    mapping (uint256 =&amp;gt; address) internal _tokenApprovals;

    mapping (address =&amp;gt; Counters.Counter) internal _ownedTokensCount;

    mapping (address =&amp;gt; mapping (address =&amp;gt; bool)) private _operatorApprovals;

    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    constructor () public {
        _registerInterface(_INTERFACE_ID_ERC721);
    }

    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), &quot;ERC721: balance query for the zero address&quot;);

        return _ownedTokensCount[owner].current();
    }

    function ownerOf(uint256 tokenId) public view returns (address) {
        address owner = _tokenOwner[tokenId];
        require(owner != address(0), &quot;ERC721: owner query for nonexistent token&quot;);

        return owner;
    }

    function approve(address to, uint256 tokenId) public {
        address owner = ownerOf(tokenId);
        require(to != owner, &quot;ERC721: approval to current owner&quot;);

        require(msg.sender == owner || isApprovedForAll(owner, msg.sender),
            &quot;ERC721: approve caller is not owner nor approved for all&quot;
        );

        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    function getApproved(uint256 tokenId) public view returns (address) {
        require(_exists(tokenId), &quot;ERC721: approved query for nonexistent token&quot;);

        return _tokenApprovals[tokenId];
    }

    function setApprovalForAll(address to, bool approved) public {
        require(to != msg.sender, &quot;ERC721: approve to caller&quot;);

        _operatorApprovals[msg.sender][to] = approved;
        emit ApprovalForAll(msg.sender, to, approved);
    }

    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    function transferFrom(address from, address to, uint256 tokenId) public {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(msg.sender, tokenId), &quot;ERC721: transfer caller is not owner nor approved&quot;);

        _transferFrom(from, to, tokenId);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, &quot;&quot;);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
        transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), &quot;ERC721: transfer to non ERC721Receiver implementer&quot;);
    }

    function _exists(uint256 tokenId) internal view returns (bool) {
        address owner = _tokenOwner[tokenId];
        return owner != address(0);
    }

    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), &quot;ERC721: operator query for nonexistent token&quot;);
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    function _burn(address owner, uint256 tokenId) internal {
        require(ownerOf(tokenId) == owner, &quot;ERC721: burn of token that is not own&quot;);

        _clearApproval(tokenId);

        _ownedTokensCount[owner].decrement();
        _tokenOwner[tokenId] = address(0);

        emit Transfer(owner, address(0), tokenId);
    }

    function _burn(uint256 tokenId) internal {
        _burn(ownerOf(tokenId), tokenId);
    }

    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from, &quot;ERC721: transfer of token that is not own&quot;);
        require(to != address(0), &quot;ERC721: transfer to the zero address&quot;);

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }

        bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
        return (retval == _ERC721_RECEIVED);
    }

    function _clearApproval(uint256 tokenId) private {
        if (_tokenApprovals[tokenId] != address(0)) {
            _tokenApprovals[tokenId] = address(0);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d5138ab7-2d3b-49e9-b998-62f5ae85ead5&quot;&gt;
&lt;p id=&quot;SE-f7fce089-1a01-44a8-b3ef-eafce2a1b678&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;a href=&quot;https://github.com/Exchange-M/NFT-ERC721/blob/master/ERC721.sol&quot;&gt;https://github.com/Exchange-M/NFT-ERC721/blob/master/ERC721.sol&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5feda654-d282-4ba5-b19e-ff6e6a73de5e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 우리는 깃허브에 배포한 파일을 가져와서 ERC721의 _mint를 구현한 후 비즈니스 로직에 집중할 수 있습니다. 기능 여하에 따라 코드를 개선한 후 올려도 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f38783c3-1e8b-4faf-8ddf-1445125f8a75&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 개선코드 적용&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div id=&quot;SE-aa82e0e9-f5a0-40e6-b542-2222c2ecc57f&quot;&gt;
&lt;pre id=&quot;code_1661637396184&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.5.0;

import 'https://github.com/Exchange-M/NFT-ERC721/blob/master/ERC721.sol';

contract ERC721Impl is ERC721 {
    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0), &quot;ERC721: mint to the zero address&quot;);
        require(!_exists(tokenId), &quot;ERC721: token already minted&quot;);

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();

        emit Transfer(address(0), to, tokenId);
    }
}

contract CharactorByERC721 is ERC721Impl{
    struct Charactor {
        string  name;  // 캐릭터 이름
        uint256 level; // 캐릭터 레벨
    }

    Charactor[] public charactors; // default: [] 
    address public owner;          // 컨트랙트 소유자

    constructor () public {
        owner = msg.sender; 
    }

    modifier isOwner() {
      require(owner == msg.sender);
      _;
    }

    // 캐릭터 생성
    function mint(string memory name, address account) public isOwner {
        uint256 cardId = charactors.length; // 유일한 캐릭터 ID
        charactors.push(Charactor(name, 1));
        _mint(account, cardId); // ERC721 소유권 등록
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-27bc1589-6970-497d-9203-9f46c1838af2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cf9d9d87-720e-4608-94e2-a652852e7a4f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 형태로 작성할 수 있습니다. 코드 자체가 훨씬 클린해졌습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e039cda3-05f5-45b5-9814-c32cd3293bc5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8e416d76-ee91-4278-b1e8-65f99bf8610d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추각적으로 ERC721 컨트랙트에 있는 메서드들 중에 _burn 또한 ERC721의 기본 인터페이스가 아니므로 상속받은 컨트랙트에서 구성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-daee2469-a572-467a-b50b-9d604541be80&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lNyI3/btrKK9K3JdR/SdeXLM6Ex9YpEq6CGw5Xc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lNyI3/btrKK9K3JdR/SdeXLM6Ex9YpEq6CGw5Xc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lNyI3/btrKK9K3JdR/SdeXLM6Ex9YpEq6CGw5Xc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlNyI3%2FbtrKK9K3JdR%2FSdeXLM6Ex9YpEq6CGw5Xc0%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;773&quot; height=&quot;483&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1684fef5-bf55-4a28-8d28-ee62f1a1a7f6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-54b6cf62-1995-442a-9ce5-1f88594017d4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정상적으로 배포된 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>165</category>
      <category>20</category>
      <category>721</category>
      <category>erc</category>
      <category>ERC165</category>
      <category>ERC20</category>
      <category>erc721</category>
      <category>Ethereum</category>
      <category>solidity</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/72</guid>
      <comments>https://meongae.tistory.com/72#entry72comment</comments>
      <pubDate>Sun, 28 Aug 2022 06:57:06 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] ERC721을 이용한 NFT 만들기 - 1편</title>
      <link>https://meongae.tistory.com/71</link>
      <description>&lt;div id=&quot;SE-5d20d6ab-37d3-4e15-826d-e24526c27eec&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-068d23fd-cd81-4eb8-aee0-6afc66f8174a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ERC721 기반의 NFT를 만들어 본 후 가볍게 실습을 진행해보는 시간을 가져보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c6a3ad66-8af6-403f-b190-028b1792e5c4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-33f93b20-5c75-4559-aa4d-cc2a0084d86d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; NFT란?&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-016793a2-1ff9-4e42-8f23-00e632c975c4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최소한 NFT가 무엇인지부터 살펴보자. NFT는 대체 불가능한 토큰을 의미합니다. 여기서 대체 불가능한 토큰이 의미하는 바가 무엇인지 알아보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-dd08aa0a-1f53-44d1-8f87-46f6e2be5d17&quot;&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0kD7z/btrKMnCiBVD/5BdAp7cm8ZfjrMt8HE0v0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0kD7z/btrKMnCiBVD/5BdAp7cm8ZfjrMt8HE0v0K/img.png&quot; data-alt=&quot;대체 가능한 토큰 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0kD7z/btrKMnCiBVD/5BdAp7cm8ZfjrMt8HE0v0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0kD7z%2FbtrKMnCiBVD%2F5BdAp7cm8ZfjrMt8HE0v0K%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;773&quot; height=&quot;295&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;대체 가능한 토큰 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-49d1e37f-c813-4bf7-9d3c-bb9cb03d7e59&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1808f129-0279-4238-a203-a28bd7099572&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 그림처럼 A와 B는 서로 1000원을 가지고 있습니다. 만약, 서로가 천원을 서로 주고받더라도 각각의 1000원은 동일한 가치를 가집니다. 여기서 1000원 대신 특정 물건으로 대체해보겠습니다. 앞의 예시와 다르게 특정 물건은 고유한 유니크 값을 가지고 있습니다. 같은 정보를 가지고 있는 데이터라고 하더라도 생성일이 다르기 때문에 유니크한 값으로 만들 수 있습니다. 이러한 특성을 대체 불가능하다고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ce8582bf-5c8c-4842-8eef-04ee343f8c49&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVFSkm/btrKHYDvetE/C3shg5bwlzivNSFrc8Iih1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVFSkm/btrKHYDvetE/C3shg5bwlzivNSFrc8Iih1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVFSkm/btrKHYDvetE/C3shg5bwlzivNSFrc8Iih1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVFSkm%2FbtrKHYDvetE%2FC3shg5bwlzivNSFrc8Iih1%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;773&quot; height=&quot;295&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ef8b13d5-8232-4e65-994e-90e11600c823&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f67350fb-9c2f-4a1d-a51d-4b53b2c4f972&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;A가 만든 캐릭터는 누가 가지고 있던간에 A가 만든 캐릭터라는 속성을 가지고 있습니다. 즉, 누가 가지고 있더라도 A가 만들었고 고유한 속성을 그대로 가지고 있습니다. 이때 이들은 데이터로 움직이기 때문에 캐릭터 정보를 다 움직이는 것이 아닌 캐릭터에 할당된 유니크한 값(ID)값으로 주고 받으며 캐릭터 하나하나를 토큰으로 취급합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d853f33b-1785-41be-9d33-d59c4394ff8b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6e5f6a6f-b18c-4344-94c7-3dfb0673de54&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약, A가 캐릭터를 10개 소유하고 있다면 10개의 토큰을 가지고 있는겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-58dd830e-5fb9-453c-ba45-5359c7c8d7c7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3f59469c-aeed-48eb-a112-a495b72ad0cc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ERC20으로 만들어진 토큰의 경우 특정 주소가 소유하고 있는 토큰을 조회하면 지불하여 사용 가능한 토큰 수량을 조회하며, ERC721로 만들어진 NFT의 경우 보유중인 대체 불가능한 무언가를 소유하고 있는 수량입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-716c2d2c-ee4e-4600-9c59-92fdf07bfdec&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-15176f64-7f5b-485a-9a08-fbade1b68c17&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 무언가는 어떻게 어떤 형태로 만드냐에 따라 결정됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c006d7fd-6aaf-4d05-a30d-02472c196223&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e126c3a7-0a38-4d89-b870-50de81faf7d4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NFT를 만들기 위해 우리는 만들어져있는 인터페이스를 활용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9aed895c-97e8-408f-8be5-0d5d686b5033&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-e6a23b0c-021a-491f-8d9e-37c855c4931c&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● NFT 구현&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-11898144-1a28-4376-922d-34aa497eea8d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NFT를 구현하기 위해 어떤 인터페이스를 제공하는지 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4668d4c9-e10d-4b6f-beca-4923c063603c&quot;&gt;
&lt;pre id=&quot;code_1661636908616&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
function supportsInterface(bytes4 interfaceID) external view returns (bool);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d0333d7f-0493-46aa-ba7f-43e8b09fcbf8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2dcb3ddd-39e6-4ffc-bd19-aedf8b16105b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리는 해당 인터페이스를 직접 구현하지 않고 구현된 인터페이스를 기반으로 우리가 원하는 기능을 구현할것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eba9c1a5-4c03-4134-a73a-4c3a515b25a5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-f2349afc-00b1-4758-9340-b2175de3221e&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; interface(인터페이스)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1661636940618&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;library Address {

    function isContract(address account) internal view returns (bool) {
        uint256 size;
        assembly { size := extcodesize(account) }
        return size &amp;gt; 0;
    }
}

library SafeMath {

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c &amp;gt;= a, &quot;SafeMath: addition overflow&quot;);

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b &amp;lt;= a, &quot;SafeMath: subtraction overflow&quot;);
        uint256 c = a - b;

        return c;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, &quot;SafeMath: multiplication overflow&quot;);

        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b &amp;gt; 0, &quot;SafeMath: division by zero&quot;);
        uint256 c = a / b;

        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, &quot;SafeMath: modulo by zero&quot;);
        return a % b;
    }
}

library Counters {
    using SafeMath for uint256;

    struct Counter {
        uint256 _value; // 기본값: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-6a512ded-c015-4baa-929f-80ce2c1c61db&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661636956705&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

contract ERC165 is IERC165 {
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    mapping(bytes4 =&amp;gt; bool) private _supportedInterfaces;

    constructor () internal {
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff, &quot;ERC165: invalid interface id&quot;);
        _supportedInterfaces[interfaceId] = true;
    }
}

contract IERC721 is IERC165 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    function balanceOf(address owner) public view returns (uint256 balance);

    function ownerOf(uint256 tokenId) public view returns (address owner);

    function safeTransferFrom(address from, address to, uint256 tokenId) public;

    function transferFrom(address from, address to, uint256 tokenId) public;
    function approve(address to, uint256 tokenId) public;
    function getApproved(uint256 tokenId) public view returns (address operator);

    function setApprovalForAll(address operator, bool _approved) public;
    function isApprovedForAll(address owner, address operator) public view returns (bool);


    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
} 

contract IERC721Receiver {
    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
    public returns (bytes4);
}
contract ERC721 is ERC165, IERC721 {
    using SafeMath for uint256;
    using Address for address;
    using Counters for Counters.Counter;

    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // 토큰 ID에서 소유자로의 매핑
    mapping (uint256 =&amp;gt; address) private _tokenOwner;

    // 토큰 ID에서 승인된 주소로의 매핑
    mapping (uint256 =&amp;gt; address) private _tokenApprovals;

    // 소유자에서 소유한 토큰 개수로의 매핑
    mapping (address =&amp;gt; Counters.Counter) private _ownedTokensCount;

    mapping (address =&amp;gt; mapping (address =&amp;gt; bool)) private _operatorApprovals;

    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    constructor () public {
        _registerInterface(_INTERFACE_ID_ERC721);
    }

    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), &quot;ERC721: balance query for the zero address&quot;);

        return _ownedTokensCount[owner].current();
    }

    function ownerOf(uint256 tokenId) public view returns (address) {
        address owner = _tokenOwner[tokenId];
        require(owner != address(0), &quot;ERC721: owner query for nonexistent token&quot;);

        return owner;
    }

    function approve(address to, uint256 tokenId) public {
        address owner = ownerOf(tokenId);
        require(to != owner, &quot;ERC721: approval to current owner&quot;);

        require(msg.sender == owner || isApprovedForAll(owner, msg.sender),
            &quot;ERC721: approve caller is not owner nor approved for all&quot;
        );

        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    function getApproved(uint256 tokenId) public view returns (address) {
        require(_exists(tokenId), &quot;ERC721: approved query for nonexistent token&quot;);

        return _tokenApprovals[tokenId];
    }

    function setApprovalForAll(address to, bool approved) public {
        require(to != msg.sender, &quot;ERC721: approve to caller&quot;);

        _operatorApprovals[msg.sender][to] = approved;
        emit ApprovalForAll(msg.sender, to, approved);
    }

    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    function transferFrom(address from, address to, uint256 tokenId) public {
        require(_isApprovedOrOwner(msg.sender, tokenId), &quot;ERC721: transfer caller is not owner nor approved&quot;);

        _transferFrom(from, to, tokenId);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, &quot;&quot;);
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
        transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), &quot;ERC721: transfer to non ERC721Receiver implementer&quot;);
    }

    function _exists(uint256 tokenId) internal view returns (bool) {
        address owner = _tokenOwner[tokenId];
        return owner != address(0);
    }

    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), &quot;ERC721: operator query for nonexistent token&quot;);
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    function _burn(address owner, uint256 tokenId) internal {
        require(ownerOf(tokenId) == owner, &quot;ERC721: burn of token that is not own&quot;);

        _clearApproval(tokenId);

        _ownedTokensCount[owner].decrement();
        _tokenOwner[tokenId] = address(0);

        emit Transfer(owner, address(0), tokenId);
    }

    function _burn(uint256 tokenId) internal {
        _burn(ownerOf(tokenId), tokenId);
    }

    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from, &quot;ERC721: transfer of token that is not own&quot;);
        require(to != address(0), &quot;ERC721: transfer to the zero address&quot;);

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }

        bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
        return (retval == _ERC721_RECEIVED);
    }

    function _clearApproval(uint256 tokenId) private {
        if (_tokenApprovals[tokenId] != address(0)) {
            _tokenApprovals[tokenId] = address(0);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f19181a8-b3ee-43a3-94d6-37c9c4c08428&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0971ca2e-8b39-44cb-a257-008ddd7cd360&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;NFT를 만들기 위해 ERC721을 구현하기 위한 인터페이스가 좀 길지만 전체적인 흐름은 토큰ID를 주고받는 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9d320d3a-f49e-4e24-bfde-608be466c678&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-711b78a5-e5d3-4a43-9dfc-a111861433de&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기본적으로 ERC721의 인터페이스는 특정 토큰이 생성되서 소유권을 부여하는 부분이 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c84c2efb-8628-4dd0-9420-a6dabbc82874&quot;&gt;
&lt;pre id=&quot;code_1661636966361&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mapping (uint256 =&amp;gt; address) private _tokenOwner;
mapping (address =&amp;gt; Counters.Counter) private _ownedTokensCount;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d307b437-1a32-4ba5-9731-ebe2885ecd92&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3c7268e5-f1af-49df-90a5-2227233ceef9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특정 토큰의 소유 주소를 가지고 있는 정보와, 특정 주소가 몇개의 토큰을 소유하고 있는지에 대한 정보를 가지고 있는 변수입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-43a0ab3c-3a8d-4933-89f8-2dde7e46adb0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-26222efa-5db8-4348-abe8-73b59c2debd8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ERC721 컨트랙트에 다음코드를 추가하여 소유권을 부여하는 _mint를 추가합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a1325ce4-9e75-4364-a785-a35f3d41d71c&quot;&gt;
&lt;pre id=&quot;code_1661636974817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contract ERC721 is ERC165, IERC721 {
    // ... 중략 ...

    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0), &quot;ERC721: mint to the zero address&quot;);
        require(!_exists(tokenId), &quot;ERC721: token already minted&quot;);

        _tokenOwner[tokenId] = to;         // 소유권 부여
        _ownedTokensCount[to].increment(); // 토큰 수량 +1

        emit Transfer(address(0), to, tokenId);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-73e41c49-e242-40c0-b9cf-91510538d291&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3ff085a6-04d4-4d21-a084-48a4c73227dc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기까지 ERC721 준비는 끝났습니다. 이제 실질적으로 대체 불가능한 무엇인가를 만들어서 tokenId를 만들어 _mint를 호출하여 소유권을 부여해주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a04f2960-f9dd-4c4b-89f5-317d25fbc7b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c8e9602b-4e03-4daa-ad27-14d919213e2b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; ERC165 알아가기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-5bc13a95-7f64-4e8d-bbe5-cb3a0c94ec15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ERC165는 해당 스마트 컨트랙트에 특정 인터페이스가 구현되어 있는지 알려줍니다. 이를 인터페이스ID라고 합니다. 인터페이스ID는 methodId들을 &lt;/span&gt;&lt;span&gt;&lt;b&gt;XOR&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 연산한 값 입니다. 이를통해 특정 메서드를 구현했는지 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2a1d224f-2e1d-4dee-866e-c5fb18838d4e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;methodId&lt;/b&gt;를 가져오는 방법은 2가지가 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eeac4f7c-cbed-4551-8934-3ad77d482a98&quot;&gt;
&lt;pre id=&quot;code_1661636987431&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contract InterfaceId {

    mapping (address =&amp;gt; uint) public balanceOf;
    
    function case2() public pure returns(bytes4, bytes4) {
        return (
            bytes4(keccak256('balanceOf(address)')), // 방법 1. methodId: 0x70a08231
            this.balanceOf.selector                  // 방법 2. methodId: 0x70a08231
        );
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-96aba9f8-cf5d-47df-b8c5-cb596c890b6b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-04f44190-1102-4912-add3-9256d7afe8f9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 코드처럼 methodId를 가져올 수 있습니다. 개인적으론 &lt;/span&gt;&lt;span&gt;&lt;b&gt;방법 2&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 선호합니다. 방법 1은 오타가 발생하면 버그를 찾기가 너무 난해해지기 때문입니다. 하지만 방법1을 사용할 때가 있습니다. 만약 다음과 같은 함수가 있다고 해봅시다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a3aeb2f5-8cfd-4488-bbef-b12ba969f3ff&quot;&gt;
&lt;pre id=&quot;code_1661637006792&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function test(uint a) public {}

function test(uint a, uint b) public {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-191442d3-05d5-4882-83cd-6f93cc721b2f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f5174b78-93f2-4354-86f8-3a326ac81e0f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;오버로딩&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 된 함수(함수명은 동일하지만 함수 인자로 구분)는 .selector를 이용하여 methodId를 가져올 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bff4f07d-bfdb-4339-9f08-c2ff74ab2d00&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bf6919d1-61d9-4326-9d14-2adc4cf9a52f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ERC165의 모습은 다음과 같습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1f9443bd-0445-4d5b-b27c-1ecef089e0fa&quot;&gt;
&lt;pre id=&quot;code_1661637017735&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

contract ERC165 is IERC165 {
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    mapping(bytes4 =&amp;gt; bool) private _supportedInterfaces;

    constructor ()  {
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff, &quot;ERC165: invalid interface id&quot;);
        _supportedInterfaces[interfaceId] = true;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-28a1a9a9-4d0e-4cc6-8acf-3e43ebc169be&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e71011bc-84a7-4ad9-b531-bd7789e98afa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;_supportedInterfaces&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 methodId(interfaceId)를 키로 가지며, 구현 유무에 따라 true, false를 저장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-685f1c02-7b42-4cc1-8d6e-238e00b57963&quot;&gt;
&lt;pre id=&quot;code_1661637024135&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-27e00daa-9b98-4d4d-a106-20e19181b659&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-77cc5400-8df1-47f6-b8ca-fc7f1d3b5ff6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;_registerInterface는 methodId가 구현되었다고 저장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4ad4dd2c-0f8c-4e6f-a884-6bae7595d43b&quot;&gt;
&lt;pre id=&quot;code_1661637030415&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff, &quot;ERC165: invalid interface id&quot;);
        _supportedInterfaces[interfaceId] = true;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-daff7740-5765-493f-80f6-c2a207d6557b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-893cb740-ddf6-42f6-9422-b981a3ca0cd0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ERC165를 상속받은 ERC721의 생성자에서 _registerInterface를 호출하여 각 인터페이스가 구현되었다는 사실을 알려줍니다. 실제로는 methodId: true 형태로 저장하고 있는 상태입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-94d1a2e5-d174-4f86-b3e3-f55ed984ed04&quot;&gt;
&lt;pre id=&quot;code_1661637036911&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 0x80ac58cd;
bytes4 private constant _INTERFACE_ID_ERC721 = 
      bytes4(keccak256('balanceOf(address)')) ^
      bytes4(keccak256('ownerOf(uint256)')) ^
      bytes4(keccak256('approve(address,uint256)')) ^
      bytes4(keccak256('getApproved(uint256)')) ^
      bytes4(keccak256('setApprovalForAll(address,bool)')) ^
      bytes4(keccak256('isApprovedForAll(address,address)')) ^
      bytes4(keccak256('transferFrom(address,address,uint256)')) ^
      bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
      bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a9e46c64-83bf-404e-a87c-b25157c752b7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-309b0ad9-686d-4b08-903e-32839344fb50&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또는 this.balanceOf.selector를 실행해도 각 메서드에 대한 methodId를 가져올 수 있습니다. this.함수.selector는 해당 함수의 methodId를 가져옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-609ec6a1-ac66-4f3d-b6c0-c41b25586e96&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;691&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MZJAD/btrKHvnZmx7/0g4WBbAMD8NdR1WMNVz3AK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MZJAD/btrKHvnZmx7/0g4WBbAMD8NdR1WMNVz3AK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MZJAD/btrKHvnZmx7/0g4WBbAMD8NdR1WMNVz3AK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMZJAD%2FbtrKHvnZmx7%2F0g4WBbAMD8NdR1WMNVz3AK%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;773&quot; height=&quot;691&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;691&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-34fc4eea-1372-4996-aa73-e57e03e9e1cc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7c2ddaef-fc1d-4031-ac25-afdf7a5dfbb6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;0x80ac58cd는 ERC721에서 제공하는 모든 함수를 구현했다는 것을 의미합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1ae56d28-7b86-4e07-a122-a9c99fd29c99&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-00c8a08f-62aa-473d-a5a9-866860ef1846&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 특정 인터페이스만 구현했다면 ERC721의 생성자(constructor)는 다음과 같이 구현할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6d063e0b-6da5-4e7c-8292-8bc94eb8466e&quot;&gt;
&lt;pre id=&quot;code_1661637044479&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;constructor ()  {
    _registerInterface(bytes4(keccak256('balanceOf(address)')) ^ bytes4(keccak256('ownerOf(uint256)')));
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4c881192-f22a-4351-b40c-e479d4c7a18e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c11fe587-b526-423d-b8e7-23af0deded73&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인터페이스에서 2개만 구현되었음을 의미합니다. 저는 일반적으로 전체를 xor한것 + 개별적인 methodId도 등록하는 것을 선호합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d2259a25-455f-4f12-9294-e57b6e9baa97&quot;&gt;
&lt;pre id=&quot;code_1661637051758&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;constructor ()  {
    _registerInterface(bytes4(keccak256('balanceOf(address)')));
    _registerInterface(bytes4(keccak256('ownerOf(uint256)')));
    _registerInterface(bytes4(keccak256('balanceOf(address)')) ^ bytes4(keccak256('ownerOf(uint256)')));
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-59e9a98b-751c-492b-a578-a6d3fcb8ea71&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-afd9ee61-f6c1-43ec-b1c6-a63fe879b5a8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 해야 개별적인 methodId를 supportsInterface()를 호출하여 해당 메서드가 구현되었는지 알 수 있기 때문입니다. 해당 코드는 selector를 이용하여 다음과 같이 수정할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7b2f1780-b58b-43e8-8ff6-8ec7483769b1&quot;&gt;
&lt;pre id=&quot;code_1661637059816&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;constructor ()  {
    _registerInterface(this.balanceOf.selector);
    _registerInterface(this.ownerOf.selector);
    _registerInterface(this.balanceOf.selector ^ this.ownerOf.selector);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-85d25eb4-e32d-464d-8b54-5f95bf8aa099&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ba3b122b-f05c-42cf-b187-de53b3566637&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 구현하는 이유는 dapp에서 특정 컨트랙트 주소를 받고 해당 컨트랙트 주소가 ERC의 표준을 잘 구현했는지 검사하는 목적으로 사용합니다. 가령 ERC20이라면 transfer 함수가 구현되어 있는지 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a018debf-6b39-4dc2-a838-36ff2cc313a5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2b74f87e-8f1a-4ba3-a6d2-9cb0167fab28&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;물론 실질적인 메서드 구현은 하지 않았지만 해당 methodId를 _registerInterface을 통해 true로 했다면 supportsInterface를 호출하는 dapp은 구현이 되었다고 인식합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0c89b1a8-17a8-4887-a594-66485bda8a40&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-cf09e192-8d6c-4be7-ad45-8b2d466f29ff&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;interfaceID 간단하게 구하는 방법이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-258d4147-cac1-4b8f-be40-c781350c6925&quot;&gt;
&lt;pre id=&quot;code_1661637075750&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.8.0;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

interface IERC721 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    function balanceOf(address owner) external view returns (uint256 balance);
    function ownerOf(uint256 tokenId) external view returns (address owner);
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;
    function approve(address to, uint256 tokenId) external;
    function getApproved(uint256 tokenId) external view returns (address operator);
    function setApprovalForAll(address operator, bool _approved) external;
    function isApprovedForAll(address owner, address operator) external view returns (bool);
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}


contract ttt  {

    function getInterfaceIDByERC20() public pure returns (bytes4) {
        return type(IERC20).interfaceId;
    }

    function getInterfaceIDByERC721() public pure returns (bytes4) {
        // bytes4 interfaceId = 
        //   this.balanceOf.selector ^
        //   this.ownerOf.selector ^
        //   this.approve.selector ^
        //   this.getApproved.selector ^
        //   this.setApprovalForAll.selector ^
        //   this.isApprovedForAll.selector ^
        //   this.transferFrom.selector ^
        //   this.safeTransferFrom.selector ^
        //   this.safeTransferFrom(address,address,uint256,bytes)')); // 0x80ac58cd
        return type(IERC721).interfaceId; // 0x80ac58cd
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e9a3e08b-5d63-46fa-98ea-2358cb9b855b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-19e8e05f-f2b2-4e55-8ef4-d16876570cc0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;type 함수에 인터페이스를 전달한후 interfaceId를 통해 interfaceId를 구할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-13749128-f635-4505-898c-b6b6881393b0&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 대체 불가능 품목 구현&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a1802be5-1574-4aba-9378-c785d2e892d3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리는 대체 불가능한 품목으로 캐릭터를 만들어 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-15f70f7d-d9c4-412a-9435-05a1104de251&quot;&gt;
&lt;pre id=&quot;code_1661637096204&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;contract CharactorByERC721 is ERC721{
    struct Charactor {
        string  name;  // 캐릭터 이름
        uint256 level; // 캐릭터 레벨
    }

    Charactor[] public charactors; // default: [] 
    address public owner;          // 컨트랙트 소유자

    constructor () public {
        owner = msg.sender; 
    }

    modifier isOwner() {
      require(owner == msg.sender);
      _;
    }

    // 캐릭터 생성
    function mint(string memory name, address account) public isOwner {
        uint256 cardId = charactors.length; // 유일한 캐릭터 ID
        charactors.push(Charactor(name, 1));
        _mint(account, cardId); // ERC721 소유권 등록
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8000a6d6-67d8-4730-bd8f-08dfd6a9ff8e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3a251a51-5530-4caa-b7af-8666545cdb22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리는 이름과 레벨 정보를 가진 캐릭터를 생성하여 대체 불가능 토큰화 시키는 코드를 완성했습니다. ERC721를 관리하는 관리자만 캐릭터를 생성할 수 있는 권한을 부여한 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6eb30450-0f20-458d-83c8-a15f199e03eb&quot;&gt;
&lt;pre id=&quot;code_1661637101652&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;modifier isOwner() {
  require(owner == msg.sender);
  _;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-84334c6c-67ba-4520-bf9e-f19f1f6ab33a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9b355d8b-3a54-4646-b182-bdba6a70b9cc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 코드가 컨트랙트 관리자인지 검사하는 코드입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-e07a2880-dc26-490a-8061-5c77ed72870b&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 동작 확인&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-f63ccbb0-c271-42c2-9f50-05dc3d5e7a79&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리는 gnache-cli로 구성한 프라이빗 네트워크에 해당 컨트랙트를 배포한 훈 remix로 테스트를 진행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c5a44399-df25-45c9-abfd-f0765f0f43da&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;&amp;middot; 컨트랙트 배포&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8c25ea67-2972-43af-8919-b48615bf5198&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-40e3cce1-0cdd-4345-b164-2f7b51380278&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661637123500&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ganache-cli

Ganache CLI v6.12.1 (ganache-core: 2.13.1)

Available Accounts
==================
(0) 0x359b3a8108140E9ef9AA1eE99989BfCb700A7998 (100 ETH)
(1) 0x40758C66149641E955eD0bBbBfE54C728967FC6d (100 ETH)
(2) 0xE5cfe607eD4a37f8F579BDd949693C5a7B470287 (100 ETH)
(3) 0x19E51f231383dF875c01fD24D9C652fD3C84f4d6 (100 ETH)
(4) 0x5b70DD2330DC3e7ABBFEc7421962A58cA2de82c4 (100 ETH)
(5) 0x448543B6d743E276618Daa0dCF948c2507Fb0AC7 (100 ETH)
(6) 0x58EDe0F214690b7eFacd97461f749152255e9C87 (100 ETH)
(7) 0x0bC225A34f03062c677543ccA21397F7F560Bd02 (100 ETH)
(8) 0x1D3278089589ff6103B8aDb807e3332Bf2c6d5d4 (100 ETH)
(9) 0x9BF35fC633e7C3eceF88B3F36082D54AD1559E8B (100 ETH)

Private Keys
==================
(0) 0x64b0ba7f1479b2ae308c16572dffdaaa8f8ebba4a992c5d6892a8d24913c001e
(1) 0x9e3d8c8dc86c2a96ac9b5b58c5f653b5cab1853f0cbf321bc0d99b3cc646e428
(2) 0x408f62d250f1f29b2f196c78583da533f0b7e7c8a097237dbc4dd24a0aee7cbd
(3) 0x88e4e9cd80515c130a59b8e060c7f12fe7f5c94046303b03fe13b48c7df55918
(4) 0x1fbcca603a2643b16e2800e9f7cfefd429a5222bfa8dd9a742d0ef43738f9c11
(5) 0xd0caf806bdac8c56255edc1bd873a93a148383cd826ce701da7092fd6aca552b
(6) 0x6c2442112c56481bb21108eb47b730d5f4c50f8b9aa626a2bad90729a80e08a3
(7) 0x25298a064037bc7f817419058552aa11b4e3a3e1777f8d26b1f5cd444af75e67
(8) 0x6d919bb336e36f515cdbeb895497eb6368a7dbace09054fbb0aeac25c24d752f
(9) 0x170bbe066cd89e1faf6bfb39348a9af9fd927da5ee700ab20521fe0384d86f39

HD Wallet
==================
Mnemonic:      local hope lawn opinion leopard rate volcano pipe opera maximum exit cube
Base HD Path:  m/44'/60'/0'/0/{account_index}

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Call Gas Limit
==================
9007199254740991

Listening on 127.0.0.1:8545&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-d0744f21-144e-486b-ad4e-5e3ef583f2ee&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ganache-cli를 이용하여 매우 편안하게 프라이빗 전용 테스트 네트워크 생성이 가능합니다. 해당 네트워크에 우리가 작성한 컨트랙트 코드를 배포해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f0348535-f0c9-4319-a017-dd2d5a1f4b56&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEHF2G/btrKHwmWfnw/oUcjJLnOSZdF5WejjkhMBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEHF2G/btrKHwmWfnw/oUcjJLnOSZdF5WejjkhMBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEHF2G/btrKHwmWfnw/oUcjJLnOSZdF5WejjkhMBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEHF2G%2FbtrKHwmWfnw%2FoUcjJLnOSZdF5WejjkhMBk%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;773&quot; height=&quot;505&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ebc33709-e5e6-4e13-8ee8-697683dce471&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9bd2a0d5-8ec6-4364-bd30-620ff3bcaefc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Deploy 버튼을 누르면 배포 완료합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-15b7c2cd-7f25-48fc-8bf0-a4228045ffe7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnAaqW/btrKGQsIoDu/EGoSY5qJR3g2ikj4VtIbxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnAaqW/btrKGQsIoDu/EGoSY5qJR3g2ikj4VtIbxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnAaqW/btrKGQsIoDu/EGoSY5qJR3g2ikj4VtIbxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnAaqW%2FbtrKGQsIoDu%2FEGoSY5qJR3g2ikj4VtIbxk%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;773&quot; height=&quot;505&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3d2a5541-8c33-40b9-a36c-4a5d0c896a1a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d57812da-9474-4fb7-b120-3677b54c0c4b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 만든 NFT의 기능을 확인할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c9d98805-5b1d-4bbe-83e9-361191eb9751&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;리믹스는 파란색/주황색 버튼으로 조회/트랜잭션 기능을 구분합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d58f413a-0c88-4288-86ac-8f1a7699afda&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0078cb; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶ 조회&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b902026e-397d-4553-9b5a-27583f471eaf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;owner 버튼(파란색)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;으로 해당 컨트랙트의 관리자를 조회할 수 있습니다. 해당 예제에선 컨트랙트 배포자를 관리자로 취급합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-338cb913-13cd-41e5-9a39-ac4519dd05af&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b233ca0f-d8a2-4009-a4fb-97f73db0608a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;balanceOf 버튼(파란색)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 전달한 주소의 보유중인 토큰수량 입니다. 여기선 캐릭터 수량이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a8af2479-0542-463a-a3ca-e88cf57bd5f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-79bc8cd4-42b1-4290-addf-371a6c35b49f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;charactors 버튼(파란색)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 토큰 아이디를 전달하여 캐릭터 정보를 조회합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a0c9dcba-b9c2-44cd-a0d3-cea2a1dc4491&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7d9f9bf4-d2cd-445c-8af6-900fb7e3c609&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;ownerOf 버튼(파란색)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 토큰 아이디를 전달하여 소유자 주소를 조회합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d962a6f0-0929-42e6-9dc5-2c6d9fb65718&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ebd824ff-c39c-44a2-b07e-b677582ef605&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;getApproved 버튼(파란색)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 특정 토큰 아이디의 전송 권한을 가진 소유자가 아닌 주소를 조회합니다.(approve 버튼으로 설정된 주소입니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9d01fbef-96bb-4bdb-b371-46e104bed073&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b6519527-dbde-4ade-b894-86fb03ffbc2d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffa94f; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;▶ transaction&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-883c7d69-a454-4fb5-93f1-34eb687faa7d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffa94f;&quot;&gt;&lt;b&gt;approve 버튼(주황색)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 소유권 이외의 전송 권한 설정&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f675a741-326e-4389-8b5c-afbc83f364e7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffa94f;&quot;&gt;&lt;b&gt;mint 버튼(주황색)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 생성된 토큰의 소유권 부여&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6efd36de-2273-4d1e-ab71-3efe29c2f198&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffa94f;&quot;&gt;&lt;b&gt;safeTransferFrom, transferFrom 버튼(주황색)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 토큰 소유권 이동&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a4d17aa7-0e36-49db-aefb-a650c3d3fb79&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-97274672-4be4-4e91-b665-488d152927fa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;transferFrom 코드를 보면 _isApprovedOrOwner() 검사를 통해 호출자가 토큰 아이디의 소유자인지 또는 approve로 등록된 주소인지 검사한 후 진행 유/무를 판단합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-36434afa-1345-4ddd-bcac-da7aba7d721d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 테스트&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cc201b53-1d4e-45ee-81d1-c37e5f385e97&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AAvPU/btrKMFbQtVC/OvIeLVJpSFnYBbaD7nYjL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AAvPU/btrKMFbQtVC/OvIeLVJpSFnYBbaD7nYjL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AAvPU/btrKMFbQtVC/OvIeLVJpSFnYBbaD7nYjL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAAvPU%2FbtrKMFbQtVC%2FOvIeLVJpSFnYBbaD7nYjL0%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;773&quot; height=&quot;539&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c6cfeb0c-d3e8-4dde-bc67-9e2899973122&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-51e20f97-1ae1-4acc-b339-a9c3de18edd4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음과 같은 정보로 mint를 호출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fa3cad6c-2d13-4045-b7b1-cf36f8c21f4b&quot;&gt;
&lt;pre id=&quot;code_1661637173665&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;name: mung-charactor
account: 0x359b3a8108140E9ef9AA1eE99989BfCb700A7998&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-55821391-1cf9-4c45-b192-3b534a5cc002&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-296a8d13-f1c7-4fc2-9ee5-90309d314830&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;토큰 아이디는 mint를 호출한 순서로 0부터 1씩 증가 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-40f2d82c-7006-48bc-991f-a66040d381b5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dB8XHZ/btrKHZPWJFq/iIaluBplj4efCCUWY9IT9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dB8XHZ/btrKHZPWJFq/iIaluBplj4efCCUWY9IT9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dB8XHZ/btrKHZPWJFq/iIaluBplj4efCCUWY9IT9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdB8XHZ%2FbtrKHZPWJFq%2FiIaluBplj4efCCUWY9IT9K%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;773&quot; height=&quot;539&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-96a9f47e-43e1-4b30-8561-a0831a27c98e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b75b27fb-a269-4e77-a2d6-d03c50f530ff&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;balanceOf,&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;charactors,&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #36851e;&quot;&gt;&lt;b&gt;ownerOf&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 보유중인 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;토큰수&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;정보 조회&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #36851e;&quot;&gt;&lt;b&gt;토큰 소유자&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 조회 결과입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-12c258e0-6a4e-4cb4-aac0-e5caa28329a3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-004f919c-c65d-4ecc-982b-16b6b9ca3c5d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 만든 토큰을 다음 주소로 전송해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-55f5dd0b-e489-4c96-8dfc-c8ddf5ed73ca&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JMmKk/btrKHwmWfrJ/0Ik5aDWQPyMoCYfahgKqGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JMmKk/btrKHwmWfrJ/0Ik5aDWQPyMoCYfahgKqGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JMmKk/btrKHwmWfrJ/0Ik5aDWQPyMoCYfahgKqGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJMmKk%2FbtrKHwmWfrJ%2F0Ik5aDWQPyMoCYfahgKqGK%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;773&quot; height=&quot;539&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8e207c8c-8225-479c-a7fa-b95760f843ce&quot;&gt;
&lt;pre id=&quot;code_1661637183305&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;0x7CA4C0d9d04E2C0F7376f47786C681b0CDbFA64E&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f165f09a-f0eb-40e0-866b-fbc73d92b30b&quot;&gt;
&lt;pre id=&quot;code_1661637188426&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from:    소유자 주소 =&amp;gt; 0x359b3a8108140E9ef9AA1eE99989BfCb700A7998
to:      수신자 주소 =&amp;gt; 0x7CA4C0d9d04E2C0F7376f47786C681b0CDbFA64E
tokenId: 토큰 아이디 =&amp;gt; 0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-646efaec-4812-4b01-a0c0-eee9cb29470d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw6tJa/btrKGn5hjrQ/QORWlgVPWrUOrCn3A7Nosk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw6tJa/btrKGn5hjrQ/QORWlgVPWrUOrCn3A7Nosk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw6tJa/btrKGn5hjrQ/QORWlgVPWrUOrCn3A7Nosk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw6tJa%2FbtrKGn5hjrQ%2FQORWlgVPWrUOrCn3A7Nosk%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;773&quot; height=&quot;539&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4313f878-a5cb-466b-a202-a2c24e8817e9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-26d12b75-277b-4eff-8088-beb326ed9847&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ownerOf와 balanceOf로 해당 토큰 소유권 이동된 걸 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8a40cc6e-afc8-41a9-bdec-3b69629f227e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/peyHi/btrKJ4QIFWo/kIrtLj7z0czvvMgR7EQsFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/peyHi/btrKJ4QIFWo/kIrtLj7z0czvvMgR7EQsFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/peyHi/btrKJ4QIFWo/kIrtLj7z0czvvMgR7EQsFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpeyHi%2FbtrKJ4QIFWo%2FkIrtLj7z0czvvMgR7EQsFK%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;429&quot; height=&quot;482&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-be2cfbf4-3bd1-4106-b0a9-72914eca0714&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7ded30b6-0c80-4d4b-b1ac-524f3a47ae51&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-c0114d87-dfb8-4b71-9df1-730ea4ebe711&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;샘플 코드는 깃허브에서 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a0d14d91-2e16-49a7-b2bb-e819e8892e35&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;SE-61f43509-4608-4acf-8a7d-3e88f49445ca&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/Exchange-M/NFT-ERC721&quot;&gt;https://github.com/Exchange-M/NFT-ERC721&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2d549c8c-03be-489e-8fae-499d6d6dcaf9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;▶ 여기서 다루는 코드는 다음 코드를 기반으로 수정되어 진행되었습니다 (참고)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://ko.docs.klaytn.com/smart-contract/sample-contracts/erc-721/1-erc721&quot;&gt;https://ko.docs.klaytn.com/smart-contract/sample-contracts/erc-721/1-erc721&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;SE-9e4320ed-47da-4971-874b-95daa4ec6375&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1661637202961&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;1. ERC-721 스마트 컨트랙트 작성 - Klaytn Docs&quot; data-og-description=&quot;MyERC721Card.sol은 하나의 인터페이스(IERC165), 세 라이브러리(Address, SafeMath 그리고 Counters) 그리고 네 컨트랙트(ERC165, IERC721, IERC721Receiver 그리고 MyERC721Card)로 구성됩니다.&quot; data-og-host=&quot;ko.docs.klaytn.foundation&quot; data-og-source-url=&quot;https://ko.docs.klaytn.com/smart-contract/sample-contracts/erc-721/1-erc721&quot; data-og-url=&quot;https://ko.docs.klaytn.foundation/smart-contract/sample-contracts/erc-721/1-erc721&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ko.docs.klaytn.com/smart-contract/sample-contracts/erc-721/1-erc721&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.docs.klaytn.com/smart-contract/sample-contracts/erc-721/1-erc721&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;1. ERC-721 스마트 컨트랙트 작성 - Klaytn Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;MyERC721Card.sol은 하나의 인터페이스(IERC165), 세 라이브러리(Address, SafeMath 그리고 Counters) 그리고 네 컨트랙트(ERC165, IERC721, IERC721Receiver 그리고 MyERC721Card)로 구성됩니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.docs.klaytn.foundation&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>165</category>
      <category>20</category>
      <category>721</category>
      <category>erc</category>
      <category>ERC165</category>
      <category>ERC20</category>
      <category>erc721</category>
      <category>NFT</category>
      <category>solidity</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/71</guid>
      <comments>https://meongae.tistory.com/71#entry71comment</comments>
      <pubDate>Sun, 28 Aug 2022 06:53:29 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] 이더리움 네트워크 모니터링 시스템 구축</title>
      <link>https://meongae.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;이번시간에는 지난번에 Ethash(POW), Clique(POA) 형태로 구축한 private network를 모니터링하는 시스템을 구축해보겠습니다.&lt;/span&gt;&lt;/p&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;a href=&quot;https://meongae.tistory.com/68&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.28 - [블록체인] - [ethereum] Geth를 이용하여 Clique(POA) 기반 private network 구축하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661636539061&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[ethereum] Geth를 이용하여 Clique(POA) 기반 private network 구축하기&quot; data-og-description=&quot;Geth를 이용하여 Ethash(POW) 기반 private network 구축하는 방법을 알아보겠습니다. ​ Geth는 POW(Ethash), POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다. ​ 지난번에 정리한 POW(Ethash) 기반으로..&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/68&quot; data-og-url=&quot;https://meongae.tistory.com/68&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bylc0S/hyPBKk1GL5/ut2pVkblKJMkvjVYZlx2k1/img.png?width=773&amp;amp;height=366&amp;amp;face=0_0_773_366,https://scrap.kakaocdn.net/dn/ccyQuQ/hyPBHIBJSE/6FuQBd6mL9u0Qv7sozzIMK/img.png?width=773&amp;amp;height=366&amp;amp;face=0_0_773_366,https://scrap.kakaocdn.net/dn/dtychp/hyPACoBWin/6GDfI7DleL0yGKMnaxr9C0/img.png?width=773&amp;amp;height=385&amp;amp;face=0_0_773_385&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/68&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/68&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bylc0S/hyPBKk1GL5/ut2pVkblKJMkvjVYZlx2k1/img.png?width=773&amp;amp;height=366&amp;amp;face=0_0_773_366,https://scrap.kakaocdn.net/dn/ccyQuQ/hyPBHIBJSE/6FuQBd6mL9u0Qv7sozzIMK/img.png?width=773&amp;amp;height=366&amp;amp;face=0_0_773_366,https://scrap.kakaocdn.net/dn/dtychp/hyPACoBWin/6GDfI7DleL0yGKMnaxr9C0/img.png?width=773&amp;amp;height=385&amp;amp;face=0_0_773_385');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[ethereum] Geth를 이용하여 Clique(POA) 기반 private network 구축하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Geth를 이용하여 Ethash(POW) 기반 private network 구축하는 방법을 알아보겠습니다. ​ Geth는 POW(Ethash), POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다. ​ 지난번에 정리한 POW(Ethash) 기반으로..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/67&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.27 - [블록체인] - [ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661636554035&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&quot; data-og-description=&quot;Geth를 이용하여 Ethash(POW) 기반 private network 구축하는 방법을 알아보겠습니다. ​ Geth는 POW(Ethash), POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다. ​ 여기선 개념적인 내용보다 방법론적인..&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/67&quot; data-og-url=&quot;https://meongae.tistory.com/67&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bHDHF2/hyPBVfMdsB/udEHwcvnSQK4Ti7S6opkf1/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/jiwWb/hyPAC3cqeF/DHl3e7CMkZaDzJXMW7AiN0/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/gm4QA/hyPBNB2KFM/z0QQJr7CikXsz4Z6Clu54K/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/67&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/67&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bHDHF2/hyPBVfMdsB/udEHwcvnSQK4Ti7S6opkf1/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/jiwWb/hyPAC3cqeF/DHl3e7CMkZaDzJXMW7AiN0/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/gm4QA/hyPBNB2KFM/z0QQJr7CikXsz4Z6Clu54K/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Geth를 이용하여 Ethash(POW) 기반 private network 구축하는 방법을 알아보겠습니다. ​ Geth는 POW(Ethash), POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다. ​ 여기선 개념적인 내용보다 방법론적인..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크는 POW, POA 어느것을 이용해도 진행가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e303ed27-7333-4556-aa3e-2cf06ff82fd8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;SE-a5849787-6d31-4318-b632-97a418248b66&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-02a76804-1c93-4561-a580-1edfe0e9074d&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 시스템 구성도&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-48d6bc64-4479-4bb2-be89-ab463ef62cee&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tqori/btrKGOBAklI/BAAO7QY7TyTCRgLuKqE0Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tqori/btrKGOBAklI/BAAO7QY7TyTCRgLuKqE0Z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tqori/btrKGOBAklI/BAAO7QY7TyTCRgLuKqE0Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftqori%2FbtrKGOBAklI%2FBAAO7QY7TyTCRgLuKqE0Z1%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;773&quot; height=&quot;236&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-041eec59-dcec-4963-accc-02b78169af58&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-6f55ef41-3e4a-40ea-acad-771c57487b3b&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● eth-netstats 구동&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-adc96742-955b-4140-8c01-9d74fe79ff17&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;eth-netstats는 실질적으로 사용자가 접속합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-292ac7b6-6d64-4ce9-ba51-d38049bcd4ac&quot;&gt;
&lt;pre id=&quot;code_1661636592095&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ git clone https://github.com/cubedro/eth-netstats.git
$ cd eth-netstats
$ npm i
$ grunt&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-84291f01-19c1-4fb4-9bbc-560adce3f064&quot;&gt;
&lt;pre id=&quot;code_1661636598265&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ export WS_SECRET=123
$ npm run start&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2c6bb8a4-eca2-4f42-93d8-2445ab298e8d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2be12d78-54dc-4e6a-a032-b9ec0ef09804&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;WS_SECRET은 Agent 서버에서 함부로 접속하지 못하게 하기 위해 설정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6b9fbaf8-a10f-4394-a7a7-5f97d52a6af8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-72227ca6-aa7c-42f8-849d-76e93ebcbd4a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;localhost:3000으로 접속하면 데이터가 비어있는 모습의 사이트가 뜹니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-28367de9-75e2-4174-938d-68ef8ad63e27&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWkw9S/btrKGyeJemA/ELovPLUHuCcF919xWxjWwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWkw9S/btrKGyeJemA/ELovPLUHuCcF919xWxjWwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWkw9S/btrKGyeJemA/ELovPLUHuCcF919xWxjWwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWkw9S%2FbtrKGyeJemA%2FELovPLUHuCcF919xWxjWwk%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;773&quot; height=&quot;432&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-334282a3-fcee-4fc9-8b56-16660939c4cb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b10ee6a3-7651-4fef-a075-ecedf27feee1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 우리는 agent 서버를 실행하여 주기적으로 노드의 정보를 해당 페이지에 뿌려줘야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-e783f73e-ecf5-42d4-a3dd-50d016e86aab&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● Agent 서버 구동&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-82882ad5-fe30-45b8-a055-b649cdaa4fa1&quot;&gt;
&lt;pre id=&quot;code_1661636612884&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ git clone https://github.com/cubedro/eth-net-intelligence-api.git
$ cd eth-net-intelligence-api
$ npm i&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ef61c261-2088-4d52-9837-1df7cc050fcd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-180c2dce-70ac-4e67-9507-54c94bcae6a5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 우리는 2개의 파일을 만들어줘야 합니다. 2개의 노드와 연결을 하기위해 노드정보를 가지고있는 json파일을 만듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-64140eae-85d0-46bb-a219-7fd5181d38c8&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; process-node1.json&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d480e55d-d87c-41fe-9bad-b3a2bdc7fcf2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5ea308c1-3406-4f7e-ba0d-24be99638fef&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661636641863&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[
  {
    &quot;name&quot;              : &quot;eth-node1&quot;,
    &quot;script&quot;            : &quot;app.js&quot;,
    &quot;log_date_format&quot;   : &quot;YYYY-MM-DD HH:mm Z&quot;,
    &quot;merge_logs&quot;        : false,
    &quot;watch&quot;             : false,
    &quot;max_restarts&quot;      : 10,
    &quot;exec_interpreter&quot;  : &quot;node&quot;,
    &quot;exec_mode&quot;         : &quot;fork_mode&quot;,
    &quot;env&quot;:
    {
      &quot;NODE_ENV&quot;        : &quot;production&quot;,
      &quot;RPC_HOST&quot;        : &quot;localhost&quot;,
      &quot;RPC_PORT&quot;        : &quot;8545&quot;,
      &quot;LISTENING_PORT&quot;  : &quot;30303&quot;,
      &quot;INSTANCE_NAME&quot;   : &quot;node1&quot;,
      &quot;CONTACT_DETAILS&quot; : &quot;&quot;,
      &quot;WS_SERVER&quot;       : &quot;http://127.0.0.1:3000/api&quot;,
      &quot;WS_SECRET&quot;       : &quot;123&quot;,
      &quot;VERBOSITY&quot;       : 2
    }
  }
]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;SE-cdcd26d4-ba0f-4d33-a33f-61053f99a159&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; process-node2.json&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e45c23f6-db41-4c98-8336-fae53598bbad&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-16dd3309-d298-4741-a1f1-04081514e859&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661636648731&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[
  {
    &quot;name&quot;              : &quot;eth-node2&quot;,
    &quot;script&quot;            : &quot;app.js&quot;,
    &quot;log_date_format&quot;   : &quot;YYYY-MM-DD HH:mm Z&quot;,
    &quot;merge_logs&quot;        : false,
    &quot;watch&quot;             : false,
    &quot;max_restarts&quot;      : 10,
    &quot;exec_interpreter&quot;  : &quot;node&quot;,
    &quot;exec_mode&quot;         : &quot;fork_mode&quot;,
    &quot;env&quot;:
    {
      &quot;NODE_ENV&quot;        : &quot;production&quot;,
      &quot;RPC_HOST&quot;        : &quot;localhost&quot;,
      &quot;RPC_PORT&quot;        : &quot;8546&quot;,
      &quot;LISTENING_PORT&quot;  : &quot;30304&quot;,
      &quot;INSTANCE_NAME&quot;   : &quot;node2&quot;,
      &quot;CONTACT_DETAILS&quot; : &quot;&quot;,
      &quot;WS_SERVER&quot;       : &quot;http://127.0.0.1:3000/api&quot;,
      &quot;WS_SECRET&quot;       : &quot;123&quot;,
      &quot;VERBOSITY&quot;       : 2
    }
  }
]&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-2a24f5aa-44df-49ba-b9aa-eb932c0dfa78&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;WS_SERVER와 WS_SECRET은 앞에서 실행한 eth-netstats서버 입니다. WS_SECRET은 앞에서 eth-netstats를 실행하기 전에 설정한 값을 넣어줍니다. WS_SERVER는 엔드포인트가 /api 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-806f55ec-5c6f-42e1-bf1a-fd52c8ac76ce&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbjvb8/btrKHVzYzYw/KwGmeYU1Nj9KImSVxpqX0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbjvb8/btrKHVzYzYw/KwGmeYU1Nj9KImSVxpqX0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbjvb8/btrKHVzYzYw/KwGmeYU1Nj9KImSVxpqX0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcbjvb8%2FbtrKHVzYzYw%2FKwGmeYU1Nj9KImSVxpqX0k%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;773&quot; height=&quot;539&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4ae1261d-ae57-49c7-8bcb-4855576d4ac3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-d3e96514-a555-459f-817d-c3ceed93b30c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Agent 실행&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-c215b664-e6e6-4551-888a-c467978fe19f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 Agent 서버를 실행해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-34ebcfba-0955-45d7-ad0b-b261e71adc5a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-848d1199-4096-46c6-a834-648c2b5328f1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661636672371&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pm2 start process-node1.json

$ pm2 start process-node2.json&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c0477b11-d4f1-47a1-ae96-45147d572a11&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661636689346&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pm2 list

┌────┬─────────────────────────┬─────────┬─────────┬──────────┬────────┬──────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name                    │ version │ mode    │ pid      │ uptime │ ↺    │ status   │ cpu      │ mem      │ user     │ watching │
├────┼─────────────────────────┼─────────┼─────────┼──────────┼────────┼──────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ 0  │ eth-node1               │ 0.1.1   │ fork    │ 54204    │ 97s    │ 0    │ online   │ 0.6%     │ 44.7mb   │ bag&amp;hellip; │ disabled │
│ 1  │ eth-node2               │ 0.1.1   │ fork    │ 54408    │ 49s    │ 0    │ online   │ 0.6%     │ 40.1mb   │ bag&amp;hellip; │ disabled │
└────┴─────────────────────────┴─────────┴─────────┴──────────┴────────┴──────┴──────────┴──────────┴──────────┴──────────┴──────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-72b1a500-2a80-433d-8243-fae82a18a0d0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;pm2는 백그라운드로 서버를 동작시킵니다. 해당 서버는 실행시 전달한 json파일에 명시된 노드에서 주기적으로 정보를 조회한 후 WS_SERVER로 전달하는 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-03c037b1-f576-4d58-918f-def30756e868&quot;&gt;
&lt;pre id=&quot;code_1661636696426&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pm2 log&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b1017a1a-8cc1-4fc6-a9de-84ab1b440e5f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tpQ2D/btrKHaqSd1X/gvxMQndNIOCKlbHLY19IK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tpQ2D/btrKHaqSd1X/gvxMQndNIOCKlbHLY19IK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tpQ2D/btrKHaqSd1X/gvxMQndNIOCKlbHLY19IK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtpQ2D%2FbtrKHaqSd1X%2FgvxMQndNIOCKlbHLY19IK0%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;773&quot; height=&quot;516&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-20cd19bc-bd30-493d-a86f-d00db34b102e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a9ce9534-0f01-43c7-8192-86418eb5eb05&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;pm2 log는 백그라운드로 동작하고 있는 서버의 로그를 출력하는 명령어입니다.&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-23634352-a191-441e-b76c-eaac98d34a09&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 실행한 eth-netstats의 로그를 확인해보면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e4885997-f0c0-480a-a6a6-d2e9925a4725&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzNK0v/btrKGp28XUv/CrK1sszJOlO9Xt2FnHMh41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzNK0v/btrKGp28XUv/CrK1sszJOlO9Xt2FnHMh41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzNK0v/btrKGp28XUv/CrK1sszJOlO9Xt2FnHMh41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzNK0v%2FbtrKGp28XUv%2FCrK1sszJOlO9Xt2FnHMh41%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;773&quot; height=&quot;516&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a715128e-83c1-48c8-9f1e-8a9dd55f79d2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bziJep/btrKHxzoOBf/4w3gitMuu8slLgdZojOfIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bziJep/btrKHxzoOBf/4w3gitMuu8slLgdZojOfIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bziJep/btrKHxzoOBf/4w3gitMuu8slLgdZojOfIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbziJep%2FbtrKHxzoOBf%2F4w3gitMuu8slLgdZojOfIK%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;773&quot; height=&quot;460&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>ETH</category>
      <category>monitor</category>
      <category>netstats</category>
      <category>Node</category>
      <category>npm</category>
      <category>모니터링</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/70</guid>
      <comments>https://meongae.tistory.com/70#entry70comment</comments>
      <pubDate>Sun, 28 Aug 2022 06:45:30 +0900</pubDate>
    </item>
    <item>
      <title>2022년 08월 27일을 기준으로 네이버 블로그에서 이관작업 시작합니다.</title>
      <link>https://meongae.tistory.com/notice/69</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기술 블로그로 기존에 운영하던 네이버 블로그를 해당 티스토리로 이관합니다.&lt;/p&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;a href=&quot;https://blog.naver.com/pjt3591oo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.naver.com/pjt3591oo&lt;/a&gt;&lt;/p&gt;</description>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/notice/69</guid>
      <pubDate>Sun, 28 Aug 2022 06:41:24 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] Geth를 이용하여 Clique(POA) 기반 private network 구축하기</title>
      <link>https://meongae.tistory.com/68</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;Geth를 이용하여 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0078cb;&quot;&gt;&lt;b&gt;Ethash(POW)&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt; 기반 private network 구축하는 방법을 알아보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-86a5436b-346c-4b3e-88a8-f287479fc2ee&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a4be4503-d267-4a7b-b2b6-e4d9b551b283&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;Geth는 POW(Ethash),&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0078cb;&quot;&gt;&lt;b&gt; POA(Clique)&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;, POS(Caspre)를 선택적으로 운용가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f3d917e2-0f91-4b64-a967-af219cce413d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3848f369-133f-4a4a-85e3-f551bbc498cd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;지난번에 정리한 POW(Ethash) 기반으로 작성한 글을 참고하면 어렵지 않게 진행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/67&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.27 - [블록체인] - [ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1661587729396&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&quot; data-og-description=&quot;Geth를 이용하여 Ethash(POW) 기반 private network 구축하는 방법을 알아보겠습니다. ​ Geth는 POW(Ethash), POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다. ​ 여기선 개념적인 내용보다 방법론적인..&quot; data-og-host=&quot;meongae.tistory.com&quot; data-og-source-url=&quot;https://meongae.tistory.com/67&quot; data-og-url=&quot;https://meongae.tistory.com/67&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XoXNq/hyPBJ7dTDo/NLAzkCdmiskGkSkI9CfiGk/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/xYFr3/hyPBRKW55h/FPswwDU22aUQcxL0SgM6T0/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/fzUMe/hyPApWP5O1/BTRH8KsAsLtjMkMftliLK1/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/67&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://meongae.tistory.com/67&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XoXNq/hyPBJ7dTDo/NLAzkCdmiskGkSkI9CfiGk/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/xYFr3/hyPBRKW55h/FPswwDU22aUQcxL0SgM6T0/img.png?width=773&amp;amp;height=513&amp;amp;face=0_0_773_513,https://scrap.kakaocdn.net/dn/fzUMe/hyPApWP5O1/BTRH8KsAsLtjMkMftliLK1/img.jpg?width=1403&amp;amp;height=1121&amp;amp;face=0_0_1403_1121');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Geth를 이용하여 Ethash(POW) 기반 private network 구축하는 방법을 알아보겠습니다. ​ Geth는 POW(Ethash), POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다. ​ 여기선 개념적인 내용보다 방법론적인..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;meongae.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;여기선 개념적인 내용보다 방법론적인 내용을 주로 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-098d5bea-22ff-4f47-a4ea-7e1dc37402d6&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: GungSeo, serif;&quot;&gt;&lt;b&gt;※ 진행순서&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1661587740269&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. allocation, mine base 지갑주소 생성
2. 첫 번째 노드 구동
3. 두 번째 노드 구동
4. 네트워크 연결
5. block, transaction broadcast 동작 테스트&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-d0f73a95-6d61-4f11-bf70-311d99134c39&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-4cbdc133-e808-416d-bbed-fe61785a0c90&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;1. 지갑주소 생성&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-7677bf85-3ee8-4a59-a9ae-6587386627ad&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;지갑주소를 생성하는 이유는 초기 이더를 할당하고 마이닝할 때 리워드(보상)을 가져갈 주소를 미리 설정해주기 위함입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ca171d99-59bf-4181-afd9-1249a8c37001&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5d3279bb-6a2f-41c7-80f2-ca46bf8264fc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;참고로 POA는 POW와 다르게 컴퓨팅 파워가 아닌 라운드 로빈을 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d34ce404-d2aa-45ce-b15e-3d2c4d3d6b4a&quot;&gt;
&lt;pre id=&quot;code_1661587778804&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir [경로] account new&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-74954293-7c90-4d6a-9a26-0398f7dcd9c2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-48533e00-0aed-4228-8e7f-d26ef664e5d4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;geth를 이용할 땐 반드시 어느경로에 저장할지 지정해줘야 합니다. 그렇지 않을경우 지정된 기본경로를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-49f71ca3-ae08-45ab-922b-8bccb0a9e92a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-39b676e2-f51d-41ee-9c51-0cb6a179b3fa&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 노드1에서 지갑생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2aadbafc-91d3-4175-8f82-e81d0ecaa9cc&quot;&gt;
&lt;pre id=&quot;code_1661587783756&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir $PWD account new&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9ca1de3b-b0cd-4059-8eab-d0232063d47d&quot;&gt;
&lt;pre id=&quot;code_1661587793156&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# node1 디렉터리에서 수행

$ geth --datadir $PWD account new   

INFO [02-19|10:04:28.072] Maximum peer count                       ETH=50 LES=0 total=50
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: 
Repeat password: 

Your new key was generated

Public address of the key:   0x5143155F92cb9d6D3a46c7d1F4413B44C8Fb3f2d
Path of the secret key file: /Users/bagjeongtae/Desktop/POA_node1/keystore/UTC--2021-02-19T01-04-29.450280000Z--5143155f92cb9d6d3a46c7d1f4413b44c8fb3f2d

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!

$ geth --datadir $PWD account new   

INFO [02-19|10:04:31.932] Maximum peer count                       ETH=50 LES=0 total=50
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: 
Repeat password: 

Your new key was generated

Public address of the key:   0x852159cDFdB2Ac32807d57782aB0217B3024fAfb
Path of the secret key file: /Users/bagjeongtae/Desktop/POA_node1/keystore/UTC--2021-02-19T01-04-33.140369000Z--852159cdfdb2ac32807d57782ab0217b3024fafb

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-81a4a206-4682-4306-8869-6eba5a6291a7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beaRgy/btrKIxL9iHI/obUqtqKI6bipbz7dYob7dK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beaRgy/btrKIxL9iHI/obUqtqKI6bipbz7dYob7dK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beaRgy/btrKIxL9iHI/obUqtqKI6bipbz7dYob7dK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeaRgy%2FbtrKIxL9iHI%2FobUqtqKI6bipbz7dYob7dK%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;773&quot; height=&quot;366&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0fa1146c-3642-47ce-a70f-e9289056ef02&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddTOJ8/btrKJ5u4ali/5wCPyCr9lUU7R9v3DkCT70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddTOJ8/btrKJ5u4ali/5wCPyCr9lUU7R9v3DkCT70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddTOJ8/btrKJ5u4ali/5wCPyCr9lUU7R9v3DkCT70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddTOJ8%2FbtrKJ5u4ali%2F5wCPyCr9lUU7R9v3DkCT70%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;773&quot; height=&quot;385&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7549e5bd-14de-4d73-bada-26f5b700f107&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-488a3f7d-d1ed-4277-8db0-729e3498d7b6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;2개의 계정을 생성해주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-df318095-1a72-4682-b79a-7da0a8b40c5d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 노드2에서 지갑생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-f38862bf-1017-43bf-ab29-a16e53fc68b2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;여기선 3개의 주소를 라운드 로빈을 하기위해 계정 하나를 더 만들어 줄건데 한개의 계정은 두 번째 노드 경로에 추가해주도록 하겠습니다. 참고로 계정은 어디에있던지 상관없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c0fa625c-67df-4ad8-9af0-f651ff90d8dd&quot;&gt;
&lt;pre id=&quot;code_1661587808604&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# node2 디렉터리에서 수행
$ geth --datadir $PWD account new   

INFO [02-19|10:08:08.105] Maximum peer count                       ETH=50 LES=0 total=50
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: 
Repeat password: 

Your new key was generated

Public address of the key:   0x444BBC8CB8aa094A76F77862d661146E0C9d6339
Path of the secret key file: /Users/bagjeongtae/Desktop/POA_node2/keystore/UTC--2021-02-19T01-08-09.485488000Z--444bbc8cb8aa094a76f77862d661146e0c9d6339

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0a9d3549-d501-4da2-bc43-ee10d9a2be59&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;229&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hw3Ic/btrKIqTLyyM/3uK0aH8lZkRuOwRnOfG7hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hw3Ic/btrKIqTLyyM/3uK0aH8lZkRuOwRnOfG7hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hw3Ic/btrKIqTLyyM/3uK0aH8lZkRuOwRnOfG7hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHw3Ic%2FbtrKIqTLyyM%2F3uK0aH8lZkRuOwRnOfG7hk%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;773&quot; height=&quot;229&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;229&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-731cd1f1-0596-49aa-8a88-ca8bdb411c3f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8SKGl/btrKIyEiesZ/Y4pn1YBtvQnkIkZTCTLsN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8SKGl/btrKIyEiesZ/Y4pn1YBtvQnkIkZTCTLsN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8SKGl/btrKIyEiesZ/Y4pn1YBtvQnkIkZTCTLsN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8SKGl%2FbtrKIyEiesZ%2FY4pn1YBtvQnkIkZTCTLsN1%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;773&quot; height=&quot;366&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fafd552c-a222-4678-8f1c-40acfc275a67&quot;&gt;
&lt;pre id=&quot;code_1661587818028&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;노드1: 0x5143155F92cb9d6D3a46c7d1F4413B44C8Fb3f2d
노드1: 0x852159cDFdB2Ac32807d57782aB0217B3024fAfb
노드2: 0x444BBC8CB8aa094A76F77862d661146E0C9d6339&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-93fddad4-9c0c-4caa-9038-33318b69c726&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-f900edf4-9c07-426e-998c-895255f94104&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;2. 첫 번째 노드 구동&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-b8fd11b2-17b5-4125-8f54-a602494b2d35&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;노드를 구동하기 전에 제네시스 블록을 생성하기 위해 제네시스 블록을 만들기 위한 파일(genesis.json)을 만들어줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d930032c-66ea-471b-8c6b-59a90f49d401&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;파일 템플릿은 POW(Ethash)와 비슷합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-6c96ed12-83f3-4562-b6ea-de604e4ae136&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; genesis.json 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f7f800b4-9eb6-4e60-b652-8c6bfa6d1256&quot;&gt;
&lt;pre id=&quot;code_1661587845429&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;config&quot;: {
    &quot;chainId&quot;: 12345,
    &quot;homesteadBlock&quot;: 0,
    &quot;eip150Block&quot;: 0,
    &quot;eip155Block&quot;: 0,
    &quot;eip158Block&quot;: 0,
    &quot;byzantiumBlock&quot;: 0,
    &quot;clique&quot;: {
      &quot;period&quot;: 5,
      &quot;epoch&quot;: 30000
    }
  },
  &quot;nonce&quot;: &quot;0x0&quot;,
  &quot;timestamp&quot;: &quot;0x5a722c92&quot;,
  &quot;extraData&quot;: &quot;0x00000000000000000000000000000000000000000000000000000000000000005143155F92cb9d6D3a46c7d1F4413B44C8Fb3f2d444BBC8CB8aa094A76F77862d661146E0C9d63390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;gasLimit&quot;: &quot;0x59A5380&quot;,
  &quot;difficulty&quot;: &quot;0x1&quot;,
  &quot;mixHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;coinbase&quot;: &quot;0x0000000000000000000000000000000000000000&quot;,
  &quot;alloc&quot;: { 
    &quot;5143155F92cb9d6D3a46c7d1F4413B44C8Fb3f2d&quot; : {
      &quot;balance&quot;: &quot;1500000000000000000000&quot;
    }
   },
  &quot;number&quot;: &quot;0x0&quot;,
  &quot;gasUsed&quot;: &quot;0x0&quot;,
  &quot;parentHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-afb39276-7e7b-4f14-bf26-d7a5f6e66232&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b7e97731-2a16-4ce3-8c2a-30458e9b7c7b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;여기서 라운드 로빈 시킬 계정을 extraData에 포함시키면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6fa7ebb9-056c-49d1-b912-de77e66bf3d1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;포함시키는 방법은 앞에서 생성한 지갑의 prefix로 붙어있는 0x를 제외하고 이어서 붙여주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-337ea131-f425-40cb-94d0-9b6bc1a824d4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ff0c87d5-f1ad-4473-bc9b-bca63a04ee19&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661587852340&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;5143155F92cb9d6D3a46c7d1F4413B44C8Fb3f2d852159cDFdB2Ac32807d57782aB0217B3024fAfb444BBC8CB8aa094A76F77862d661146E0C9d6339&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-b7fae57a-b84f-4c3c-879a-de690cb50a5b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;[라운드 로빈 계정] 부분에 앞의 문자열로 대체합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661587860244&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;config&quot;: {
    &quot;chainId&quot;: 12345,
    &quot;homesteadBlock&quot;: 0,
    &quot;eip150Block&quot;: 0,
    &quot;eip155Block&quot;: 0,
    &quot;eip158Block&quot;: 0,
    &quot;byzantiumBlock&quot;: 0,
    &quot;clique&quot;: {
      &quot;period&quot;: 5,
      &quot;epoch&quot;: 30000
    }
  },
  &quot;nonce&quot;: &quot;0x0&quot;,
  &quot;timestamp&quot;: &quot;0x5a722c92&quot;,
  &quot;extraData&quot;: &quot;0x00000000000000000000000000000000000000000000000000000000000000005143155F92cb9d6D3a46c7d1F4413B44C8Fb3f2d852159cDFdB2Ac32807d57782aB0217B3024fAfb444BBC8CB8aa094A76F77862d661146E0C9d63390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;gasLimit&quot;: &quot;0x59A5380&quot;,
  &quot;difficulty&quot;: &quot;0x1&quot;,
  &quot;mixHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;coinbase&quot;: &quot;0x0000000000000000000000000000000000000000&quot;,
  &quot;alloc&quot;: {  },
  &quot;number&quot;: &quot;0x0&quot;,
  &quot;gasUsed&quot;: &quot;0x0&quot;,
  &quot;parentHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d253e22b-34bb-4a13-8a91-82da2841da45&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a31f3d47-6a35-4bb4-ad1f-987a3a4a999e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;clique.period는 트랜잭션이 발생하지 않을때 블록생성 주기입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-98e9fbbd-5b4c-4557-b3d9-84ebb452a5f6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; genesis.json 초기화&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-975b3201-57d4-4d40-9402-472ba97f1fa6&quot;&gt;
&lt;pre id=&quot;code_1661587895996&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir [경로] init [제네시스파일 경로]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5e2ecb3e-7e08-4014-a287-0d2bef0e9b0b&quot;&gt;
&lt;pre id=&quot;code_1661587905276&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$  geth --datadir $PWD init genesis.json

INFO [02-19|10:24:39.001] Maximum peer count                       ETH=50 LES=0 total=50
INFO [02-19|10:24:39.021] Set global gas cap                       cap=25000000
INFO [02-19|10:24:39.021] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/POA_node1/geth/chaindata cache=16.00MiB handles=16
INFO [02-19|10:24:39.099] Writing custom genesis block 
INFO [02-19|10:24:39.100] Persisted trie from memory database      nodes=0 size=0.00B time=&quot;20.641&amp;micro;s&quot; gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-19|10:24:39.101] Successfully wrote genesis state         database=chaindata hash=&quot;8a08d7&amp;hellip;b5ee63&quot;
INFO [02-19|10:24:39.101] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/POA_node1/geth/lightchaindata cache=16.00MiB handles=16
INFO [02-19|10:24:39.194] Writing custom genesis block 
INFO [02-19|10:24:39.194] Persisted trie from memory database      nodes=0 size=0.00B time=&quot;4.418&amp;micro;s&quot;  gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-19|10:24:39.195] Successfully wrote genesis state         database=lightchaindata hash=&quot;8a08d7&amp;hellip;b5ee63&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-55c64447-2ebb-4b67-a15c-16670e42fedc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XYZ6n/btrKLhosXDG/ExdfbESqxZ1UlNKAnnL2sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XYZ6n/btrKLhosXDG/ExdfbESqxZ1UlNKAnnL2sk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XYZ6n/btrKLhosXDG/ExdfbESqxZ1UlNKAnnL2sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXYZ6n%2FbtrKLhosXDG%2FExdfbESqxZ1UlNKAnnL2sk%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;773&quot; height=&quot;200&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d0dfcbd8-0279-445e-96b4-1c54be6d66fe&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-17b7aa04-4ce6-465c-bae3-1b82e0aebfd4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;여기까지 작업을 정상적으로 마쳤다면 다음과 같이 결과를 얻습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5231afc4-371a-478e-bf62-cd8e4135096f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6wUbQ/btrKF1gQdH5/uBR9ak3OEqX5OBEpmQY36K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6wUbQ/btrKF1gQdH5/uBR9ak3OEqX5OBEpmQY36K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6wUbQ/btrKF1gQdH5/uBR9ak3OEqX5OBEpmQY36K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6wUbQ%2FbtrKF1gQdH5%2FuBR9ak3OEqX5OBEpmQY36K%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;773&quot; height=&quot;366&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-302a533b-d5aa-4194-9542-9aeae1cc82cd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-17a70c16-a931-48bd-9106-8b1943b239bf&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 노드실행&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7efb8756-8f40-4662-b283-02c41fe6416a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661587918628&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth \
--datadir $PWD \
--syncmode 'full' \
--allow-insecure-unlock \
--networkid 12345 \
--maxpeers 3 \
--http \
--http.port 8545 \
--http.addr &quot;0.0.0.0&quot; \
--http.corsdomain &quot;*&quot; \
--http.api &quot;admin,eth,debug,miner,net,txpool,personal,web3&quot; \
--ws \
--ws.port 3334 \
--ws.api eth,net,web3 \
--port 30303 \
--gasprice 21000 \
--nodiscover \
--unlock '0x5143155f92cb9d6d3a46c7d1f4413b44c8fb3f2d' \
--password password.txt \
console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a75edaa1-66fb-418c-8858-3196d12af7cf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3d3c30f1-58d4-4808-b275-454094141362&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;unlock은 해당 노드에서 라운드 로빈에 등록된 extraData에서 하나 또는 컴마로 구분하여 지갑을 나열합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-53fba0dc-3a01-46b0-a778-9399f36d38f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7ed0eaaa-7384-46cb-97a8-06f151c50f86&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;--password 옵션으로 전달하는 파일은 --unlock에 등록한 계정들의 키스토어파일 비밀번호를 작성합니다. 만약 --unlock에 컴마로 여러 지갑을 나열했다면 엔터로 구분하여 각각의 비밀번호를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3fb236a4-0d38-466e-b8c0-f067fd73331f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0f42fefb-d4aa-4225-a59f-f6c97a9246cb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;275&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2nyFR/btrKGSjqzG5/xachuaDbZV9ovmkOviegj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2nyFR/btrKGSjqzG5/xachuaDbZV9ovmkOviegj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2nyFR/btrKGSjqzG5/xachuaDbZV9ovmkOviegj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2nyFR%2FbtrKGSjqzG5%2FxachuaDbZV9ovmkOviegj1%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;773&quot; height=&quot;275&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;275&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;pre id=&quot;code_1661587926316&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;p&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f4325fcf-7044-4271-bfc6-4a84aec5e7c0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-44c81e2f-e303-4cd5-b9ca-d0e2eafe47d6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;추후 노드 연결을 위해 enode를 잘 기억해둡시다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-94206098-efa0-49eb-979d-07900b3dfca3&quot;&gt;
&lt;pre id=&quot;code_1661587934652&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enode://6e7cdfbb3ca0194187b4ce9acbd3db77f603cf197881ca3ae8598e94ce5c679f0fda5945995b87f666d090467bf3706a584856ce5e86453fff27be34669eb3d6@127.0.0.1:30303?discport=0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-312bfbf0-3eb5-48f8-a08d-b96c6d747396&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-b14c0175-eac5-4d98-9e9b-a76852436ee2&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;3. 두 번째 노드 구동&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 id=&quot;SE-5aee6abb-2165-4625-87f2-687303f30fc3&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; genesis.json 파일 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-7cca6920-1b39-44e6-943c-6659b495a158&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;첫 번째 노드 구동 시 사용하던 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;&lt;b&gt;genesis.json&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;을 가져옵니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8fab4972-5bca-4aaf-98a0-cb5cb7af63af&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c87qcs/btrKHdHGGZs/kbmbpSB2943r5WpKowKxAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c87qcs/btrKHdHGGZs/kbmbpSB2943r5WpKowKxAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c87qcs/btrKHdHGGZs/kbmbpSB2943r5WpKowKxAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc87qcs%2FbtrKHdHGGZs%2FkbmbpSB2943r5WpKowKxAk%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;773&quot; height=&quot;366&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ba1a9406-9447-41b7-8e4d-14f10d4c42cc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7844be1d-eb16-4b79-adc7-a4c6e6c2ce66&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-3af4d41f-957a-4344-a575-32f2cbaee589&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 제네시스 블록 초기화&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1319a3df-791c-4c73-b01f-d29e85896194&quot;&gt;
&lt;pre id=&quot;code_1661587957148&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$  geth --datadir $PWD init genesis.json

INFO [02-19|10:29:12.788] Maximum peer count                       ETH=50 LES=0 total=50
INFO [02-19|10:29:12.805] Set global gas cap                       cap=25000000
INFO [02-19|10:29:12.805] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/POA_node2/geth/chaindata cache=16.00MiB handles=16
INFO [02-19|10:29:12.888] Writing custom genesis block 
INFO [02-19|10:29:12.889] Persisted trie from memory database      nodes=0 size=0.00B time=&quot;19.063&amp;micro;s&quot; gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-19|10:29:12.889] Successfully wrote genesis state         database=chaindata hash=&quot;8a08d7&amp;hellip;b5ee63&quot;
INFO [02-19|10:29:12.889] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/POA_node2/geth/lightchaindata cache=16.00MiB handles=16
INFO [02-19|10:29:12.963] Writing custom genesis block 
INFO [02-19|10:29:12.963] Persisted trie from memory database      nodes=0 size=0.00B time=&quot;3.692&amp;micro;s&quot;  gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-19|10:29:12.964] Successfully wrote genesis state         database=lightchaindata hash=&quot;8a08d7&amp;hellip;b5ee63&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-38c3d387-4913-44e4-b60c-62bb5f362c62&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2a4030c8-bd2d-46ce-8277-3b51bc22d5ed&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;첫 번째 노드에서 제네시스 블록을 생성할 때 사용한 명령어와 동일합니다. 다만 해당 명령어를 수행하는 위치가 다릅니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-964037ad-8261-46fd-a8e6-6be7ab7f1c6b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nLlAO/btrKHv2lj34/kRjVIksWcXOnkWhfqrVEI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nLlAO/btrKHv2lj34/kRjVIksWcXOnkWhfqrVEI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nLlAO/btrKHv2lj34/kRjVIksWcXOnkWhfqrVEI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnLlAO%2FbtrKHv2lj34%2FkRjVIksWcXOnkWhfqrVEI0%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;773&quot; height=&quot;161&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a678d934-304f-4e5d-afa8-886c708acbe0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9b90eb8b-02d1-40d6-9a2f-1e192d6e3926&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;제네시스 블록으로 생성된 데이터의 위치가 다른것을 확인할 수 있습니다.&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-82bf492b-1688-4727-a9e0-b9b08ed0d690&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 노드실행&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ec8436eb-8f1b-482a-a791-8c0299ec5604&quot;&gt;
&lt;pre id=&quot;code_1661587968603&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth \
--datadir $PWD \
--syncmode 'full' \
--allow-insecure-unlock \
--networkid 12345 \
--maxpeers 3 \
--http \
--http.port 8546 \
--http.addr &quot;0.0.0.0&quot; \
--http.corsdomain &quot;*&quot; \
--http.api &quot;admin,eth,debug,miner,net,txpool,personal,web3&quot; \
--ws \
--ws.port 3335 \
--ws.api eth,net,web3 \
--port 30304 \
--gasprice 21000 \
--nodiscover \
--unlock '0x444bbc8cb8aa094a76f77862d661146e0c9d6339' \
--password password.txt \
console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ab7853ac-9257-4f44-86c2-5adf22db5470&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-8eac8a00-5316-467c-9f5e-94ac8e6bfcd6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;두 번째 노드를 실행할 때 중요한 건 이미 실행중인 첫 번째 노드에서 사용중인 포트를 곂치지 않게 해야합니다. 다음 3개를 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8f475097-421c-4e59-8c26-49fbb12a3fa1&quot;&gt;
&lt;pre id=&quot;code_1661587975099&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;--http.port
--ws.port
--port&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f1262d4-d080-4186-bb71-64c79b3d3211&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-bc664f22-7eef-426b-b646-f5fc5f4e769d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;첫 번째 노드와 마찬가지로 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;unlock은 해당 노드에서 라운드 로빈에 등록된 extraData에서 하나 또는 컴마로 구분하여 지갑을 나열합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b97557a8-b995-4228-b029-73c3617fd709&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;--password 옵션으로 전달하는 파일은 --unlock에 등록한 계정들의 키스토어파일 비밀번호를 작성합니다. 만약 --unlock에 컴마로 여러 지갑을 나열했다면 엔터로 구분하여 각각의 비밀번호를 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-78275514-d9c5-4739-b012-696d0204ac76&quot;&gt;
&lt;pre id=&quot;code_1661587982741&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;p&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e0a27c41-46af-4edd-ac66-90cbf5ea4513&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQ9KJM/btrKHZhPCWA/O7e7Og2bujpo3JiXl0LAh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQ9KJM/btrKHZhPCWA/O7e7Og2bujpo3JiXl0LAh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQ9KJM/btrKHZhPCWA/O7e7Og2bujpo3JiXl0LAh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQ9KJM%2FbtrKHZhPCWA%2FO7e7Og2bujpo3JiXl0LAh0%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;773&quot; height=&quot;270&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1a48b171-f0fb-415f-8b03-3b4be6fa22b5&quot;&gt;
&lt;pre id=&quot;code_1661587992019&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enode://8938590dd2a17a48d23025d6e7cbb13549ca9f75374651665e38adf45cbf9c3ad4478a804bcfdf59c12f34f005d2e6842e43ceadbb680e52069dd9de2879d060@127.0.0.1:30304?discport=0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4133c5cd-f268-4cce-9dd1-129abbafa6d0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-36401b86-aeb5-45d7-8f14-85e54c0ae539&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;4. 노드연결&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5924265c-55e0-4711-8454-0a025b2e9c4a&quot;&gt;
&lt;pre id=&quot;code_1661588005077&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;노드1: enode://6e7cdfbb3ca0194187b4ce9acbd3db77f603cf197881ca3ae8598e94ce5c679f0fda5945995b87f666d090467bf3706a584856ce5e86453fff27be34669eb3d6@127.0.0.1:30303?discport=0
노드2: enode://8938590dd2a17a48d23025d6e7cbb13549ca9f75374651665e38adf45cbf9c3ad4478a804bcfdf59c12f34f005d2e6842e43ceadbb680e52069dd9de2879d060@127.0.0.1:30304?discport=0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-584166d5-1a4d-4f11-8317-e17d2aada8b2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1305420e-d201-4f59-bcbd-469a529f43b1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;노드1에서 admin.addPeer(노드2 enode) 또는 노드2에서 admin.addPeer(노드1 enode)를 호출합니다. 저는 전자의 방법을 택하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5fe57c0d-7e79-4667-bc7e-9dbe0ee1d383&quot;&gt;
&lt;pre id=&quot;code_1661588017515&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; admin.addPeer(&quot;enode://8938590dd2a17a48d23025d6e7cbb13549ca9f75374651665e38adf45cbf9c3ad4478a804bcfdf59c12f34f005d2e6842e43ceadbb680e52069dd9de2879d060@127.0.0.1:30304?discport=0&quot;)
&amp;gt; true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-18488fd0-4c07-4596-8186-18797cb053d7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-d221602d-3a74-415f-9bdf-1713c439891f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;노드 1, 2에서 admin.peers로 각 노드에서 연결하고 있는 노드를 조회할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-afae633a-6e57-4524-a207-a1206b62c4f9&quot;&gt;
&lt;pre id=&quot;code_1661588026579&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; admin.peers
[{
    caps: [&quot;eth/63&quot;, &quot;eth/64&quot;, &quot;eth/65&quot;],
    enode: &quot;enode://8938590dd2a17a48d23025d6e7cbb13549ca9f75374651665e38adf45cbf9c3ad4478a804bcfdf59c12f34f005d2e6842e43ceadbb680e52069dd9de2879d060@127.0.0.1:30304?discport=0&quot;,
    id: &quot;8d125f8fe3f7b157ec183d250253b14eff3c4577beee63c6e147a0286289bfe1&quot;,
    name: &quot;Geth/v1.9.25-stable-e7872729/darwin-amd64/go1.15.6&quot;,
    network: {
      inbound: false,
      localAddress: &quot;127.0.0.1:51676&quot;,
      remoteAddress: &quot;127.0.0.1:30304&quot;,
      static: true,
      trusted: false
    },
    protocols: {
      eth: {
        difficulty: 1,
        head: &quot;0x8a08d70a448f3708d9dbd6d405af8d566e9e93a99ae3324df0603ce9c8b5ee63&quot;,
        version: 65
      }
    }
}]

&amp;gt; net
{
  listening: true,
  peerCount: 1,
  version: &quot;10&quot;,
  getListening: function(callback),
  getPeerCount: function(callback),
  getVersion: function(callback)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a25cf94b-9a35-4556-9205-277d9af81e09&quot;&gt;
&lt;pre id=&quot;code_1661588034995&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; admin.peers
[{
    caps: [&quot;eth/63&quot;, &quot;eth/64&quot;, &quot;eth/65&quot;],
    enode: &quot;enode://6e7cdfbb3ca0194187b4ce9acbd3db77f603cf197881ca3ae8598e94ce5c679f0fda5945995b87f666d090467bf3706a584856ce5e86453fff27be34669eb3d6@127.0.0.1:51676&quot;,
    id: &quot;c1eb472449d4ca9f46f9ccaac1beae1d65d8faf022514996302570651ebaa054&quot;,
    name: &quot;Geth/v1.9.25-stable-e7872729/darwin-amd64/go1.15.6&quot;,
    network: {
      inbound: true,
      localAddress: &quot;127.0.0.1:30304&quot;,
      remoteAddress: &quot;127.0.0.1:51676&quot;,
      static: false,
      trusted: false
    },
    protocols: {
      eth: {
        difficulty: 1,
        head: &quot;0x8a08d70a448f3708d9dbd6d405af8d566e9e93a99ae3324df0603ce9c8b5ee63&quot;,
        version: 65
      }
    }
}]

&amp;gt; net
{
  listening: true,
  peerCount: 1,
  version: &quot;10&quot;,
  getListening: function(callback),
  getPeerCount: function(callback),
  getVersion: function(callback)
}
&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7cec097d-376e-48e1-b431-0781f417b617&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1gFPO/btrKHbbWpnx/lUmgToBt6lSn5UlAmmR5i1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1gFPO/btrKHbbWpnx/lUmgToBt6lSn5UlAmmR5i1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1gFPO/btrKHbbWpnx/lUmgToBt6lSn5UlAmmR5i1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1gFPO%2FbtrKHbbWpnx%2FlUmgToBt6lSn5UlAmmR5i1%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;773&quot; height=&quot;372&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;372&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0d3cc96b-9b8c-46ed-b769-3e0c689ea8d9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-1d05801c-eea9-488d-bda3-b126301e9cd6&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;5. 동작 테스트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-10ab962e-798c-40bb-a178-597f393a3d54&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;POA 기반에선 miner.start()를 실행하면 컴퓨팅 리소스가 아니라 트랜잭션 발생시 extraData에 등록한 지갑 순서대로 블록생성을 합니다. 이 방법을 &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;&lt;b&gt;라운드로빈&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;이라고 부릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-7651d3bc-cfe1-41b2-a5f9-0c32da44ea76&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 발생&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-51c1d298-6496-4777-a986-5fdfba47a620&quot;&gt;
&lt;pre id=&quot;code_1661588050395&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: 12321})

INFO [02-19|11:40:47.383] Setting new local account                address=0x5143155F92cb9d6D3a46c7d1F4413B44C8Fb3f2d
INFO [02-19|11:40:47.383] Submitted transaction                    fullhash=0xf4c848358401bf56f0f28fc0831558bd520f8c09d1d80c2172bed25e32cb7061 recipient=0x852159cDFdB2Ac32807d57782aB0217B3024fAfb
&quot;0xf4c848358401bf56f0f28fc0831558bd520f8c09d1d80c2172bed25e32cb7061&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8c1241c7-3a84-434d-b2d2-1f4b4bd1a934&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-36e69984-e19a-4568-822a-fbf51b5a66fc&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; POA 구동시작&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-af6e8bca-82c0-4fa9-8078-52d50a2e6464&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;각 노드에서 miner.start()를 해야 각 노드에서 POA를 위해 등록한 주소를 블록생산에 참가 시킬 수 있습니다. 첫 번째, 두 번째 노드에서 POA 구동을 해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-aaf6816f-ae6e-4050-b3fc-250800e18a22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1e868b1d-cd11-42c7-a4a4-ca9140517029&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;한가지 중요한 점은 extraData에 포함한 계정 갯수(POA에 참가한 지갑)가 N개일 때 (N/2 +1)개 만큼 구동되야 정상적으로 POA를 구동합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-30d6032f-5c74-44b0-ab66-1e35727888a2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-23ff3423-ce58-4b26-ad32-98a7df0f7326&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;역기선 2개를 등록했기 때문에 2/2 + 1 = 2개가 구동되어야 동작하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a374ba76-4614-4885-81ae-a92099f527b4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4da27612-4bdb-4712-9ceb-1d6afbb170ff&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661588063459&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INFO [02-19|12:01:25.005]   mined potential block                  number=193 hash=&quot;229f58&amp;hellip;6d0ce6&quot;
INFO [02-19|12:01:25.005] Commit new mining work                   number=194 sealhash=&quot;d9511f&amp;hellip;87a806&quot; uncles=0 txs=0 gas=0     fees=0         elapsed=&quot;269.905&amp;micro;s&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-23f97031-691e-49bf-aa51-c729f90ac331&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;블록을 생성할 때 로그입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e8fa11cc-764e-414c-b35c-17836816abed&quot;&gt;
&lt;pre id=&quot;code_1661588071847&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INFO [02-19|12:01:50.008] Imported new chain segment               blocks=1 txs=0 mgas=0.000 elapsed=&quot;184.608&amp;micro;s&quot; mgasps=0.000   number=198 hash=&quot;84dc69&amp;hellip;708e32&quot; dirty=6.59KiB&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-39105f40-3b07-456d-b84a-4c2316b54603&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-7da82649-9515-4a79-8731-4a6bb643725b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;블록을 전달받을 때 로그입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-08-27 오후 5.16.14.png&quot; data-origin-width=&quot;2233&quot; data-origin-height=&quot;1234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4xmoU/btrKGREOpHk/Hr77mJl7beUJeEUYHW3eU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4xmoU/btrKGREOpHk/Hr77mJl7beUJeEUYHW3eU1/img.png&quot; data-alt=&quot;[그림 1.1] 실행된 노드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4xmoU/btrKGREOpHk/Hr77mJl7beUJeEUYHW3eU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4xmoU%2FbtrKGREOpHk%2FHr77mJl7beUJeEUYHW3eU1%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;2233&quot; height=&quot;1234&quot; data-filename=&quot;스크린샷 2022-08-27 오후 5.16.14.png&quot; data-origin-width=&quot;2233&quot; data-origin-height=&quot;1234&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.1] 실행된 노드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;div id=&quot;SE-e8c559ac-d3e2-45b8-910f-7b83650ebb92&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cfb05ac1-e6df-4922-8fa6-e0359d1ef4e5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;마이닝을 하게 되면 [그림 1.1]에서 가장위의 노드는 unlock과 password를 전달하지 않는 노드입니다. 즉 블록생성을 하지 않고 아래 두 노드가 unlock과 password를 전달하여 블록 생성을 하는 노드입니다. 첫 번째 노드에서 트랜잭션을 발생하면 2, 3번째 노드가 트랜잭션을 전달받아 순차적으로 블록을 생성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c92b5e01-71bc-47d6-ac3a-a97cf35565f6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ec895e51-7fc6-4847-8c70-f3f7eec2e6db&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;일반적으로 private 네트워크를 운용할 땐 POW보단 POA를 이용하는 방법을 권장합니다. 그 이유는 POW에 비해 POA는 컴퓨터 리소스를 거의 사용하지 않기 때문에 훨씬 안정적으로 운용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2d232c8e-ca14-476b-a13c-f2c529bab3d1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0bb8a3d4-0a83-4ab5-8f69-4463de71daf5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;이번시간엔 Geth를 이용하여 POA 기반의 private network를 구축하는 방법을 알아보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-745ddcc1-ae35-486c-bf2f-7fbdbeef55e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-38a51e93-5757-408b-a13e-de7cb3361fb5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666;&quot;&gt;다음 시간엔 지난번에 구축한 POW 환경과 여기서 만든 POA 환경의 private 네트워크망에서 노드 모니터링을 연동해보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3d00ca3c-8ba1-4f78-8f3f-b6f4929f9e85&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-27332410-3c50-44cc-b950-08b704a58518&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #608cba;&quot;&gt;&lt;u&gt;&lt;/u&gt;&lt;u&gt;&lt;a href=&quot;https://ethstats.net/&quot;&gt;https://ethstats.net/&lt;/a&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5aeb5d44-eea9-48f3-a9e6-80608aa0e27b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #608cba;&quot;&gt;&lt;u&gt;​&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>Clique</category>
      <category>Ethereum</category>
      <category>geth</category>
      <category>period</category>
      <category>POA</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/68</guid>
      <comments>https://meongae.tistory.com/68#entry68comment</comments>
      <pubDate>Sun, 28 Aug 2022 06:40:02 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] Geth를 이용하여 Ethash 기반 private network 구축하기</title>
      <link>https://meongae.tistory.com/67</link>
      <description>&lt;div id=&quot;SE-0eb20c33-1c41-4af5-9ea0-f5706f0311cf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5655eea9-2ba7-4a02-9afd-0644ca75979b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Geth를 이용하여 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;Ethash(POW)&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 기반 private network 구축하는 방법을 알아보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-716ad831-1bbc-46d5-ac0e-ee8e6a779157&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c554f575-5afa-4e41-af14-01a3b0e5307d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Geth는 &lt;/span&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;POW(Ethash)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, POA(Clique), POS(Caspre)를 선택적으로 운용가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e7427273-ac64-4b02-be93-13b81d7ed5fd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-77c1d0bd-f419-47f0-96e1-6c9b5619138c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기선 개념적인 내용보다 방법론적인 내용을 주로 다룹니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a2cdd882-cff0-442e-a50c-eaea6a629970&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-28394627-04dc-4a8e-b56e-0a92f1a390de&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● GETH 다운로드&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-739f1b0c-e41e-422c-a49e-03d59303b90a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://geth.ethereum.org/downloads/&quot;&gt;https://geth.ethereum.org/downloads/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-39112140-4961-4fc9-9967-fd0ac126ad8b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a64b26cc-327f-4fe8-b713-dbe8cc14537b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c1d7c3d1-17b0-475d-aa9f-cbb8df944d45&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 링크에 접속하면 OS별로 GETH 실행프로그램을 설치할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b0b4e347-9497-4835-a604-1568bd4c3c91&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;513&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ADUes/btrKJ3RxEpE/4Qn3JSjSV6g5sSDaLOTNo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ADUes/btrKJ3RxEpE/4Qn3JSjSV6g5sSDaLOTNo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ADUes/btrKJ3RxEpE/4Qn3JSjSV6g5sSDaLOTNo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FADUes%2FbtrKJ3RxEpE%2F4Qn3JSjSV6g5sSDaLOTNo1%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;773&quot; height=&quot;513&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;513&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cff8ff0a-ae05-413c-abd1-da0f123154ce&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-33732a06-5d25-4a93-bc90-8c7ca119f40c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9c394e7e-69a4-41f7-8eba-7802d034d0a1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;private 네트워크 구축을 위에 필요한 준비는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b2b0129e-ac81-4314-ab02-d9f52df524cf&quot;&gt;
&lt;pre id=&quot;code_1661587146129&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. allocation, mine base 지갑주소 생성
2. 첫 번째 노드 생성
3. 두 번째 노드 생성
4. 네트워크 연결
5. block, transaction broadcast 동작 테스트&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-cd2e446f-ad3d-4fb6-94e9-47de84e59848&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-cfbb2d06-1a6e-4402-8f8b-518b549fc66c&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1. 지갑주소 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e806f083-d17b-4de3-b706-89d4d4e7f20d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장먼저, 지갑주소를 생성해주는 이유는 초기에 이더를 할당하고 마이닝할 때 리워드(보상)을 가져갈 주소를 미리 설정해주기 위함입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3d5e8e4f-ea44-4a8c-89f8-c2a10a50ebce&quot;&gt;
&lt;pre id=&quot;code_1661587162096&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir [경로] account new&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-31124e36-49a5-4509-a325-a42accbf45d4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-586df1ba-a12a-4932-99d0-11f7142a4ef0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;항상 geth 또는 parity를 이용할 땐 어느 디렉터리를 기준으로 명령어를 수행할 지 반드시 전달해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b27fb37f-9cae-4f21-a2a8-5bc43a8a2847&quot;&gt;
&lt;pre id=&quot;code_1661587174000&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir $PWD account new            

INFO [02-16|21:22:15.157] Maximum peer count                       ETH=50 LES=0 total=50
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: 패스워드 입력
Repeat password: 패스워드 입력

Your new key was generated

Public address of the key:   0x04dEb80cc89c42D8148312CFC16E1579E4aF7291
Path of the secret key file: /Users/bagjeongtae/Desktop/node1/keystore/UTC--2021-02-16T12-22-16.603245000Z--04deb80cc89c42d8148312cfc16e1579e4af7291

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d3987f51-e234-45d9-ad92-442280f7e361&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-47c7b279-7243-4714-9755-00b9738fa4ac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;$PWD는 현재 터미널이 가리키고 있는 위치를 의미하며 비밀번호를 입력하라고 뜹니다. 해당 비밀번호는 private key를 keystore로 변환하기 위해 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a3825a17-97c0-4914-9d28-e422ae75ba24&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s5HZm/btrKHZa1SrJ/X8szMkxxpdowT1pOvW08R1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s5HZm/btrKHZa1SrJ/X8szMkxxpdowT1pOvW08R1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s5HZm/btrKHZa1SrJ/X8szMkxxpdowT1pOvW08R1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs5HZm%2FbtrKHZa1SrJ%2FX8szMkxxpdowT1pOvW08R1%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;773&quot; height=&quot;366&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4459c40e-8a78-4a29-a49b-4ddaf276d0ce&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ff32a2c4-f781-477a-8c78-5bbe9e915654&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;$PWD는 node1 디렉터리를 가리키고 있으며 디렉터리 아래에 private key와 비밀번호를 결합하여 만들어진 keystore 파일을 보관합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1661587185191&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir $PWD account new

INFO [02-16|21:24:27.530] Maximum peer count                       ETH=50 LES=0 total=50
Your new account is locked with a password. Please give a password. Do not forget this password.
Password: 
Repeat password: 

Your new key was generated

Public address of the key:   0x56F11a78100226558194655c0eAbf64F9627181D
Path of the secret key file: /Users/bagjeongtae/Desktop/node1/keystore/UTC--2021-02-16T12-24-28.547579000Z--56f11a78100226558194655c0eabf64f9627181d

- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;SE-b07347fd-f7b0-41d4-8eff-885b4e4ee428&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id=&quot;SE-d44e8b54-815f-427a-bbbc-82d23d501032&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NHn6t/btrKIr6cyHK/JxUB30DwEKVqOiffkK07u1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NHn6t/btrKIr6cyHK/JxUB30DwEKVqOiffkK07u1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NHn6t/btrKIr6cyHK/JxUB30DwEKVqOiffkK07u1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNHn6t%2FbtrKIr6cyHK%2FJxUB30DwEKVqOiffkK07u1%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;773&quot; height=&quot;366&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-85f3063e-008e-4ca6-aba4-90546d115c81&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-aac42b68-8372-4fa2-9f5a-5b0589e2513b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게해서 만들어진 주소는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-19f86a6c-924e-4d7a-a8c7-df62e8ff85dc&quot;&gt;
&lt;pre id=&quot;code_1661587194207&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;0x04dEb80cc89c42D8148312CFC16E1579E4aF7291
0x56F11a78100226558194655c0eAbf64F9627181D&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-23748615-522b-4e15-8ee9-18191d9ee309&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a982d5ae-8473-43a0-b599-10ff90ada0de&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;혹시 keystore 파일에 대해서 궁금하신 분은 다음 링크를 통해 확인해보세요.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://meongae.tistory.com/56&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2022.08.27 - [블록체인] - [ethereum] keystore 파일에 대해서&lt;/a&gt;&lt;/p&gt;
&lt;div id=&quot;SE-5713222f-d945-48d4-a736-1276c390df21&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-d8b0b14b-3c26-4d05-b9d4-5c06ed9e408c&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;2. 첫 번째 노드 생성&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-520d80de-4ea5-4bef-950f-05e23d424487&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 과정은 스킵하고 넘어갈 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-6c5f4e5d-a65f-453a-9b42-3c6222e3484d&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; genesis 블록 정의&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-3e871689-e355-4e5d-acfe-6bcb0b7f5822&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;genesis 블록을 만들기 위해 정보를 정의해줘야 합니다. 기본폼은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-874794cb-debf-4259-a897-cc2c225a6ef5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3bc2bb87-75c3-45b0-a17b-94ec4d863132&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 가독성을 위해 &lt;/span&gt;&lt;span&gt;&lt;b&gt;genesis.json&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이라고 파일을 만들어 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f7974307-4555-4672-88c3-a3313f933de4&quot;&gt;
&lt;pre id=&quot;code_1661587248415&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;config&quot;: {
    &quot;chainId&quot;: 10,
    &quot;homesteadBlock&quot;: 0,
    &quot;eip150Block&quot;: 0,
    &quot;eip155Block&quot;: 0,
    &quot;eip158Block&quot;: 0,
    &quot;byzantiumBlock&quot;: 0,
    &quot;constantinopleBlock&quot;: 0,
    &quot;petersburgBlock&quot;: 0,
    &quot;istanbulBlock&quot;: 0
  },
  &quot;coinbase&quot;   : &quot;0x0&quot;,
  &quot;nonce&quot;: &quot;0x0000000000000033&quot;,
  &quot;timestamp&quot;: &quot;0x0x177AACF3671&quot;,
  &quot;parentHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;gasLimit&quot;: &quot;0x8000000&quot;,
  &quot;difficulty&quot;: &quot;0x100&quot;,
  &quot;mixhash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;alloc&quot;: {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b809b9f2-11ea-4dd1-9cf6-adc24460ce65&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-1cfd7540-f07e-4b0e-8924-ac0d228635bb&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; config&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-576fb131-3179-4965-987f-abdcbf01ebf9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 부분은 geth의 버전등을 표현합니다. 해당 정보가 잘못되면 추후에 노드간 연결 및 broadcast가 원할히 진행되지 않거나 transaction이 정상적으로 발생하지 않을 수 있습니다. 항상 사용하고 있는 geth 및 parity 같은 클라이언트 프로그램의 버전에 맞춰서 작성해야 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-28bd6e73-264f-4ae2-ad91-929e5d7cfb8f&quot;&gt;
&lt;pre id=&quot;code_1661587260006&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;여기서 사용한 geth 버전은 다음과 같습니다. 
1.9.25-stable-e7872729&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-13397342-ccf5-4a5e-90db-166f99937b4d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-0815c9c5-c285-416b-9272-eadba8b91c37&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; coinbase&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-223da74c-a926-4747-8ae0-5c96b6a39d0b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마이닝 했을 때 보상받을 지갑주소 .해당값은 추후에 바꿀 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-60648753-84a4-41b3-965d-7dd910d63593&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 해당값을 입력할 땐 prefix로 0x를 반드시 붙여줘야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-f97a9574-b8fd-4a9c-b7e9-06b9f151eea1&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; nonce&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-c5d6262c-c9e2-4ea8-a5a2-7535eea38e95&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;POW 알고리즘에 사용하는 파라미터 초기설정 입니다. 알고리즘이 동작하면서 해당값을 바뀌게 됩니다. 크게 신경쓰지 않아도 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-2a3dd1ad-dc20-4ee0-b9d3-af7c55cdd5e4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; timestamp&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-2984ec5b-69c5-44cf-b8ea-8bd0a0f71f1c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 블록이 만들어진 시간입니다. 당연히 timestamp의 16진수로 변환된 값을 넣어줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-c627eda6-e7de-4455-8754-f2d27338ae5f&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; parantHash&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-93e50583-2380-4432-800d-4287ed726f60&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이전블록 해쉬값인데 첫 번째 블록의 이전 블록은 없기 때문에 0x0으로 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-0b3e145c-9325-412e-9aa9-da98fd012445&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; gasLimit&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-a2e324e7-3b51-48a1-ab74-dfbf088cd67c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;말 그대로 해당 노드에서 최대로 처리할 수 있는 gas 입니다. gas는 연료의 개념으로 이더 전송의 기본 가스 소모량은 21000이며, 스마트컨트랙트는 실행된 코드에 따라 달라지게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-58f976bf-58d6-4efb-9184-d951578155e9&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; difficulty&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-80394bb5-c619-4e9e-b137-9ddf1cc1451d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;nonce와 마찬가지로 POW 알고리즘 동작에 사용되는 파라미터이며, 알고리즘에 의해 값은 변경됩니다. 블록생성 주기가 10~20초 사이가 되도록 맞춰집니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-42664da1-6251-445b-9d4a-6e50d370a131&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; alloc&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-f49b7fd5-7618-44e7-ae4b-00abb57cfd95&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;초기에 state를 정의하는 부분입니다. 즉, 이더리움을 특정 지갑에 할당하거나 스마트 컨트랙트를 배포하는 용도입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4e98682f-2c6e-483d-ab64-8fb0ca2c7658&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;alloc은 coinbase와 다르게 prefix로 포함된 0x를 지워야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6696cfbc-dbae-4bf9-8b87-45bc1d308887&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-023846b3-a405-4ec1-bf1e-c7768b2c25dd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 앞에서 생성한 주소를 기반으로 만들어진 genesis 블록(genesis.json) 정보는 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-489db1bc-ec65-4337-822e-254fddbf01da&quot;&gt;
&lt;pre id=&quot;code_1661587329222&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;config&quot;: {
    &quot;chainId&quot;: 10,
    &quot;homesteadBlock&quot;: 0,
    &quot;eip150Block&quot;: 0,
    &quot;eip155Block&quot;: 0,
    &quot;eip158Block&quot;: 0,
    &quot;byzantiumBlock&quot;: 0,
    &quot;constantinopleBlock&quot;: 0,
    &quot;petersburgBlock&quot;: 0,
    &quot;istanbulBlock&quot;: 0
  },
  &quot;coinbase&quot;   : &quot;0x04dEb80cc89c42D8148312CFC16E1579E4aF7291&quot;,
  &quot;nonce&quot;: &quot;0x0000000000000033&quot;,
  &quot;timestamp&quot;: &quot;0x177AACF3671&quot;,
  &quot;parentHash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;gasLimit&quot;: &quot;0x8000000&quot;,
  &quot;difficulty&quot;: &quot;0x100&quot;,
  &quot;mixhash&quot;: &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;alloc&quot;: {
    &quot;04dEb80cc89c42D8148312CFC16E1579E4aF7291&quot;: { 
        &quot;balance&quot;: &quot;500000000000000000000000&quot; 
    },
    &quot;56F11a78100226558194655c0eAbf64F9627181D&quot;: { 
        &quot;balance&quot;: &quot;800000000000000000000000&quot; 
     }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f0d9ba60-4baa-49d6-bac8-daade4b06a2b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1bf87eb1-fbe0-46b7-8829-3294ef0cc077&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-427e790e-f49e-4dc7-a3ac-810f32472a25&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 제네시스 블록 초기화&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-52d3d1b4-f710-43f7-851a-a1932cc2ae22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;제네시스 블록을 정의한 파일을 기반으로 제네시스 블록을 초기화 하기 위해 &lt;/span&gt;&lt;span&gt;&lt;b&gt;init&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 명령어를 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a5b8166f-e22a-499a-ab65-7b823596f55f&quot;&gt;
&lt;pre id=&quot;code_1661587350309&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir [경로] init [제네시스파일 경로]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ba48341e-718b-41f7-b132-94d26857f4ee&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-23fb2b06-f520-4c96-a96f-9a1724b1408a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;당연히 datadir을 전달해야 해당 경로에 초기블록 정보를 저장합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-99f8cf5b-3077-48a0-8490-80fc84f5af87&quot;&gt;
&lt;pre id=&quot;code_1661587364714&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir $PWD init genesis.json

INFO [02-16|21:41:12.661] Maximum peer count                       ETH=50 LES=0 total=50
INFO [02-16|21:41:12.692] Set global gas cap                       cap=25000000
INFO [02-16|21:41:12.692] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/node1/geth/chaindata cache=16.00MiB handles=16
INFO [02-16|21:41:12.765] Writing custom genesis block 
INFO [02-16|21:41:12.766] Persisted trie from memory database      nodes=3 size=411.00B time=&quot;205.117&amp;micro;s&quot; gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-16|21:41:12.767] Successfully wrote genesis state         database=chaindata hash=&quot;2bd1fd&amp;hellip;2ba123&quot;
INFO [02-16|21:41:12.767] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/node1/geth/lightchaindata cache=16.00MiB handles=16
INFO [02-16|21:41:12.840] Writing custom genesis block 
INFO [02-16|21:41:12.841] Persisted trie from memory database      nodes=3 size=411.00B time=&quot;142.937&amp;micro;s&quot; gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-16|21:41:12.841] Successfully wrote genesis state         database=lightchaindata hash=&quot;2bd1fd&amp;hellip;2ba123&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b5f782f9-b282-4845-b8bb-f7379221d4bd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;139&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cppuON/btrKHT9HOBT/vMrN9Kkn9SSyMx8WpJrbsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cppuON/btrKHT9HOBT/vMrN9Kkn9SSyMx8WpJrbsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cppuON/btrKHT9HOBT/vMrN9Kkn9SSyMx8WpJrbsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcppuON%2FbtrKHT9HOBT%2FvMrN9Kkn9SSyMx8WpJrbsk%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;773&quot; height=&quot;139&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2fd23291-ac5a-45b4-a5c2-98286c149330&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-57afe4c2-8797-4a12-ae62-54918faa8bf0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기까지 작업을 정상적으로 마쳤다면 다음과 같이 결과를 얻습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a0852359-0733-4049-ad86-fded6d5166a9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9YZ5V/btrKHcWhe6j/K8MMsBHp7NCXpYgcOUmCe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9YZ5V/btrKHcWhe6j/K8MMsBHp7NCXpYgcOUmCe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9YZ5V/btrKHcWhe6j/K8MMsBHp7NCXpYgcOUmCe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9YZ5V%2FbtrKHcWhe6j%2FK8MMsBHp7NCXpYgcOUmCe0%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;773&quot; height=&quot;366&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-43dbf725-2519-4b97-8569-eb74d0e792ef&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-12bfe208-641e-43ff-b765-eae6536ec2a3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자 이제 첫번째 노드를 실행시킬 준비를 마쳤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0194f110-a3e3-4b2b-b8f5-c97e636703cb&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-05563755-20b5-441c-864a-a922a448d169&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 노드실행&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e4f3a18d-9760-433f-98d8-ac931b1f5819&quot;&gt;
&lt;pre id=&quot;code_1661587378941&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth \
--datadir $PWD \
--syncmode 'full' \
--allow-insecure-unlock \
--networkid 10 \
--maxpeers 3 \
--http \
--http.port 8545 \
--http.addr &quot;0.0.0.0&quot; \
--http.corsdomain &quot;*&quot; \
--http.api &quot;admin,eth,debug,miner,net,txpool,personal,web3&quot; \
--ws \
--ws.port 3334 \
--ws.api eth,net,web3 \
--port 30303 \
--gasprice 21000 \
--nodiscover \
console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6a279c5b-cd4d-4dc7-82d6-2073a0b3fa68&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b16a1198-50d3-4295-ae97-bec015c43729&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실행 옵션이 상당히 많은데 옵션 설명은 일단 스킵하고 넘어가겠습니다. 앞의 명령어를 수행하면 다음과 같이 로그가 출력되면서 대기상태가 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d7c8a97b-0319-4438-8edd-5cebf27d4b0d&quot;&gt;
&lt;pre id=&quot;code_1661587388829&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INFO [02-16|21:46:39.824] Maximum peer count                       ETH=3 LES=0 total=3
WARN [02-16|21:46:39.857] The flag --gasprice is deprecated and will be removed in the future, please use --miner.gasprice 
INFO [02-16|21:46:39.857] Set global gas cap                       cap=25000000
INFO [02-16|21:46:39.857] Allocated trie memory caches             clean=256.00MiB dirty=256.00MiB
INFO [02-16|21:46:39.857] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/node1/geth/chaindata cache=512.00MiB handles=5120
INFO [02-16|21:46:40.144] Opened ancient database                  database=/Users/bagjeongtae/Desktop/node1/geth/chaindata/ancient
INFO [02-16|21:46:40.145] Initialised chain configuration          config=&quot;{ChainID: 10 Homestead: 0 DAO: &amp;lt;nil&amp;gt; DAOSupport: false EIP150: 0 EIP155: 0 EIP158: 0 Byzantium: 0 Constantinople: 0 Petersburg: 0 Istanbul: 0, Muir Glacier: &amp;lt;nil&amp;gt;, YOLO v2: &amp;lt;nil&amp;gt;, Engine: unknown}&quot;
INFO [02-16|21:46:40.145] Disk storage enabled for ethash caches   dir=/Users/bagjeongtae/Desktop/node1/geth/ethash count=3
INFO [02-16|21:46:40.145] Disk storage enabled for ethash DAGs     dir=/Users/bagjeongtae/Library/Ethash count=2
INFO [02-16|21:46:40.145] Initialising Ethereum protocol           versions=&quot;[65 64 63]&quot; network=10 dbversion=&amp;lt;nil&amp;gt;
WARN [02-16|21:46:40.145] Upgrade blockchain database version      from=&amp;lt;nil&amp;gt; to=8
INFO [02-16|21:46:40.147] Loaded most recent local header          number=0 hash=&quot;2bd1fd&amp;hellip;2ba123&quot; td=256 age=0
INFO [02-16|21:46:40.147] Loaded most recent local full block      number=0 hash=&quot;2bd1fd&amp;hellip;2ba123&quot; td=256 age=0
INFO [02-16|21:46:40.147] Loaded most recent local fast block      number=0 hash=&quot;2bd1fd&amp;hellip;2ba123&quot; td=256 age=0
INFO [02-16|21:46:40.147] Regenerated local transaction journal    transactions=0 accounts=0
INFO [02-16|21:46:40.148] Starting peer-to-peer node               instance=Geth/v1.9.25-stable-e7872729/darwin-amd64/go1.15.6
INFO [02-16|21:46:40.148] Mining too far in the future             wait=1943952h23m17.269s
INFO [02-16|21:46:40.276] New local node record                    seq=1 id=b3a7bc0f70f798d1 ip=127.0.0.1 udp=0 tcp=30303
INFO [02-16|21:46:40.277] Started P2P networking                   self=&quot;enode://3d161a305a562575f7ca7a3e99dc5254556fc126098e4128644fb580e3b83fd6fc5ad27ef721428d1473115442c7150da15c6f7a2ff08edd7623ca9dd0e192ba@127.0.0.1:30303?discport=0&quot;
INFO [02-16|21:46:40.277] IPC endpoint opened                      url=/Users/bagjeongtae/Desktop/node1/geth.ipc
INFO [02-16|21:46:40.278] HTTP server started                      endpoint=[::]:8545 cors=* vhosts=localhost
INFO [02-16|21:46:40.278] WebSocket enabled                        url=ws://127.0.0.1:3334
INFO [02-16|21:46:40.329] Etherbase automatically configured       address=0x04dEb80cc89c42D8148312CFC16E1579E4aF7291
Welcome to the Geth JavaScript console!

instance: Geth/v1.9.25-stable-e7872729/darwin-amd64/go1.15.6
coinbase: 0x04deb80cc89c42d8148312cfc16e1579e4af7291
at block: 0 (Sun Feb 05 53099 09:16:49 GMT+0900 (KST))
 datadir: /Users/bagjeongtae/Desktop/node1
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

To exit, press ctrl-d

&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a805c081-5df3-408c-baa5-21f26690cef3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsrS1w/btrKHwtqa8I/w9dFkmpAAmyLx6SvuVw1V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsrS1w/btrKHwtqa8I/w9dFkmpAAmyLx6SvuVw1V0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsrS1w/btrKHwtqa8I/w9dFkmpAAmyLx6SvuVw1V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsrS1w%2FbtrKHwtqa8I%2Fw9dFkmpAAmyLx6SvuVw1V0%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;773&quot; height=&quot;234&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a28b6368-7418-4ba9-a687-a4bf550d742b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-13e7f3e2-14af-4cda-b8c2-862028e0ba09&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;저는 start.sh 파일을 만들어 앞의 명령어를 실행했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-89fceb62-bbcc-47a5-b79b-c02cd199303c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ec60b51c-d19f-4ce8-95d3-a0ccd55f9b27&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 명령어를 통해 앞에서 생성한 keystore 파일을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a5f8cdf8-8d75-4e1b-a290-bf62256d9247&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1f82f238-c95a-457e-8b16-e838ade00092&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661587397325&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.accounts
[&quot;0x04deb80cc89c42d8148312cfc16e1579e4af7291&quot;, &quot;0x56f11a78100226558194655c0eabf64f9627181d&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-956016ae-09b0-4939-8963-d7b8af008ae4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-67000ceb-a5ea-4233-9d22-052a0a44d74b&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;3. 두 번째 노드 생성&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-3e4031e1-d963-49e6-a5ed-2a8199948b10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서부터 상당히 중요합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-431536fb-b023-486c-b99c-f0cd5f5f77f5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-b8b3e912-abe8-4a4b-8c25-5362264dc74b&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; genesis 블록 정의&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-2be096c6-8f19-4ca9-a3a8-463b0324503e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 제네시스 파일을 별도로 만들지 않고 앞에서 만든 제네시스 파일을 그대로 사용하여 초기화 작업을 진행해야 합니다. 또한 두 번째 노드 디렉터리에 &lt;/span&gt;&lt;span&gt;&lt;b&gt;keystore/&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가&lt;/span&gt;&lt;span&gt; 없어도 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7c0e68e6-85a2-435f-9d9a-2fae9d7d67b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e01cfd7e-8960-4725-86bd-c28ab74824ee&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 일단 두 번째 노드가 데이터를 저장할 디렉터리를 새로 만들어 준 후 앞에서 만든 &lt;/span&gt;&lt;span&gt;&lt;b&gt;genesis.json&lt;/b&gt;&lt;/span&gt;&lt;span&gt;을 그대로 복사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-86bb8651-28ef-4ea2-bcb1-759262658adf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjwMrj/btrKHw1hwHZ/PrFfXKvI2iwNlvGbRiax11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjwMrj/btrKHw1hwHZ/PrFfXKvI2iwNlvGbRiax11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjwMrj/btrKHw1hwHZ/PrFfXKvI2iwNlvGbRiax11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjwMrj%2FbtrKHw1hwHZ%2FPrFfXKvI2iwNlvGbRiax11%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;773&quot; height=&quot;366&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-402e299f-4364-418a-90fc-2c2035a14df3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-181fbfbe-bad0-4d40-801f-344fbe2a356e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;&amp;middot; 제네시스 블록 초기화&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2e8c29a5-695d-4329-b58c-da49d054c5a5&quot;&gt;
&lt;pre id=&quot;code_1661587417205&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth --datadir $PWD init genesis.json      
        
INFO [02-16|21:53:34.096] Maximum peer count                       ETH=50 LES=0 total=50
INFO [02-16|21:53:34.119] Set global gas cap                       cap=25000000
INFO [02-16|21:53:34.119] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/node2/geth/chaindata cache=16.00MiB handles=16
INFO [02-16|21:53:34.240] Writing custom genesis block 
INFO [02-16|21:53:34.241] Persisted trie from memory database      nodes=3 size=411.00B time=&quot;208.877&amp;micro;s&quot; gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-16|21:53:34.242] Successfully wrote genesis state         database=chaindata hash=&quot;2bd1fd&amp;hellip;2ba123&quot;
INFO [02-16|21:53:34.242] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/node2/geth/lightchaindata cache=16.00MiB handles=16
INFO [02-16|21:53:34.317] Writing custom genesis block 
INFO [02-16|21:53:34.317] Persisted trie from memory database      nodes=3 size=411.00B time=&quot;130.919&amp;micro;s&quot; gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [02-16|21:53:34.318] Successfully wrote genesis state         database=lightchaindata hash=&quot;2bd1fd&amp;hellip;2ba123&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7ad1d610-d680-45dc-b201-407a8c599633&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fcf37447-0fdc-4bf5-958a-879c7d22c572&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 노드에서 제네시스 블록을 생성할 때 사용한 명령어와 동일합니다. 다만 해당 명령어를 수행하는 위치가 다릅니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e5d7e1a9-e333-4c95-9c76-5396e681e9c4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uSn1K/btrKHc9OgTi/3LwuE9mcPX999OmZTeZoZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uSn1K/btrKHc9OgTi/3LwuE9mcPX999OmZTeZoZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uSn1K/btrKHc9OgTi/3LwuE9mcPX999OmZTeZoZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuSn1K%2FbtrKHc9OgTi%2F3LwuE9mcPX999OmZTeZoZk%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;773&quot; height=&quot;129&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b8f99f41-1841-4eaa-a72c-a92a2a8775ef&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e62a0415-2de6-4591-9739-70334960a910&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;제네시스 블록으로 생성된 데이터의 위치가 다른것을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b74913f4-0a0f-44e0-b3b9-5eabdfc46c40&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-fc9a816a-80d3-4987-8dbd-84c0a78c4f52&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 노드실행&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-5ed201f0-d3bc-4813-a6b6-abd1dd614aa0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;노드 실행준비가 벌써 끝났습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-47b07d97-51f3-4e3b-be9b-8a537791406a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b4b8d7b9-78cd-45d5-b10a-dde92c5808ed&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 개념이 상당히 잡히지 않을 수 있는데 여기선 개념 설명은 깊게 다루지 않겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ebd35dc6-3a65-405f-9567-a48b0ff8443b&quot;&gt;
&lt;pre id=&quot;code_1661587431461&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ geth \
--datadir $PWD \
--syncmode 'full' \
--allow-insecure-unlock \
--networkid 10 \
--maxpeers 3 \
--http \
--http.port 8546 \
--http.addr &quot;0.0.0.0&quot; \
--http.corsdomain &quot;*&quot; \
--http.api &quot;admin,eth,debug,miner,net,txpool,personal,web3&quot; \
--ws \
--ws.port 3335 \
--ws.api eth,net,web3 \
--port 30304 \
--gasprice 21000 \
--nodiscover \
console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a03fbc25-870c-423d-8785-56480fd2f35d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b1c0d6d7-08c7-498d-b20b-ed85b825e64b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;두 번째 노드를 실행할 때 중요한 건 이미 실행중인 첫 번째 노드에서 사용중인 포트를 곂치지 않게 해야합니다. 다음 3개를 수정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f9679637-4736-4310-92a1-2ad15e907ee7&quot;&gt;
&lt;pre id=&quot;code_1661587437645&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;--http.port
--ws.port
--port&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8386b9e0-2d8e-40e7-9d86-8dc0ce46fa95&quot;&gt;
&lt;pre id=&quot;code_1661587446493&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INFO [02-16|21:57:57.180] Maximum peer count                       ETH=3 LES=0 total=3
WARN [02-16|21:57:57.202] The flag --gasprice is deprecated and will be removed in the future, please use --miner.gasprice 
INFO [02-16|21:57:57.202] Set global gas cap                       cap=25000000
INFO [02-16|21:57:57.202] Allocated trie memory caches             clean=256.00MiB dirty=256.00MiB
INFO [02-16|21:57:57.202] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/node2/geth/chaindata cache=512.00MiB handles=5120
INFO [02-16|21:57:57.633] Opened ancient database                  database=/Users/bagjeongtae/Desktop/node2/geth/chaindata/ancient
INFO [02-16|21:57:57.634] Initialised chain configuration          config=&quot;{ChainID: 10 Homestead: 0 DAO: &amp;lt;nil&amp;gt; DAOSupport: false EIP150: 0 EIP155: 0 EIP158: 0 Byzantium: 0 Constantinople: 0 Petersburg: 0 Istanbul: 0, Muir Glacier: &amp;lt;nil&amp;gt;, YOLO v2: &amp;lt;nil&amp;gt;, Engine: unknown}&quot;
INFO [02-16|21:57:57.634] Disk storage enabled for ethash caches   dir=/Users/bagjeongtae/Desktop/node2/geth/ethash count=3
INFO [02-16|21:57:57.634] Disk storage enabled for ethash DAGs     dir=/Users/bagjeongtae/Library/Ethash count=2
INFO [02-16|21:57:57.634] Initialising Ethereum protocol           versions=&quot;[65 64 63]&quot; network=10 dbversion=&amp;lt;nil&amp;gt;
WARN [02-16|21:57:57.634] Upgrade blockchain database version      from=&amp;lt;nil&amp;gt; to=8
INFO [02-16|21:57:57.634] Loaded most recent local header          number=0 hash=&quot;2bd1fd&amp;hellip;2ba123&quot; td=256 age=0
INFO [02-16|21:57:57.634] Loaded most recent local full block      number=0 hash=&quot;2bd1fd&amp;hellip;2ba123&quot; td=256 age=0
INFO [02-16|21:57:57.634] Loaded most recent local fast block      number=0 hash=&quot;2bd1fd&amp;hellip;2ba123&quot; td=256 age=0
INFO [02-16|21:57:57.635] Regenerated local transaction journal    transactions=0 accounts=0
INFO [02-16|21:57:57.635] Mining too far in the future             wait=1943952h12m0.269s
INFO [02-16|21:57:57.635] Starting peer-to-peer node               instance=Geth/v1.9.25-stable-e7872729/darwin-amd64/go1.15.6
INFO [02-16|21:57:57.747] New local node record                    seq=1 id=4f2e17d5582c40f7 ip=127.0.0.1 udp=0 tcp=30304
INFO [02-16|21:57:57.747] Started P2P networking                   self=&quot;enode://f550e6c4d4da21ce708c7eab69db995e76059325c08111738ebbf62545ce9430c02148b4e87c4884c41dfc0dd3034fc55e75757341f0f954686e548426f51f02@127.0.0.1:30304?discport=0&quot;
INFO [02-16|21:57:57.748] IPC endpoint opened                      url=/Users/bagjeongtae/Desktop/node2/geth.ipc
INFO [02-16|21:57:57.748] HTTP server started                      endpoint=[::]:8546 cors=* vhosts=localhost
INFO [02-16|21:57:57.749] WebSocket enabled                        url=ws://127.0.0.1:3335
WARN [02-16|21:57:57.793] Served eth_coinbase                      reqid=3 t=&quot;22.714&amp;micro;s&quot; err=&quot;etherbase must be explicitly specified&quot;
Welcome to the Geth JavaScript console!

instance: Geth/v1.9.25-stable-e7872729/darwin-amd64/go1.15.6
at block: 0 (Sun Feb 05 53099 09:16:49 GMT+0900 (KST))
 datadir: /Users/bagjeongtae/Desktop/node2
 modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

To exit, press ctrl-d
&amp;gt; INFO [02-16|21:58:00.511] Mapped network port                      proto=tcp extport=30304 intport=30304 interface=&quot;UPNP IGDv1-IP1&quot;
&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7579783d-3914-439e-a797-b40652825fa0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GN7Gy/btrKHaxkslv/NN09odgeHrwoR1PtQ6Kt60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GN7Gy/btrKHaxkslv/NN09odgeHrwoR1PtQ6Kt60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GN7Gy/btrKHaxkslv/NN09odgeHrwoR1PtQ6Kt60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGN7Gy%2FbtrKHaxkslv%2FNN09odgeHrwoR1PtQ6Kt60%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;773&quot; height=&quot;217&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aabca776-c3b4-4092-9a29-b571e30c5259&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-56c7aee2-cb3b-4328-932f-35b56821262d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실행을 정상적으로 마쳤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9de08f66-3fe7-4e3a-95a7-e41938c1f86b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ddc5ed25-1a01-4c71-9426-78a27bf37811&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기까지 이더리움 싱글노드 구축을 완료입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b3b760d2-19a7-4aa0-ade1-b9ef3626e93e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-7ac3b801-aa6d-4d98-a8f3-e08ef88e1891&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;4. 노드 동작 &amp;amp; 노드연결&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-a5f50896-2928-4805-b985-8240d099b027&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 우리가 만든 노드를 하나의 시스템으로 묶어주기 위해 연결해줘야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3ca89e0a-eea9-4726-aac9-5837ac49f590&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;681&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAARq6/btrKHUAMBrk/qEJfDf3L8vmpqkf8G6zRx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAARq6/btrKHUAMBrk/qEJfDf3L8vmpqkf8G6zRx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAARq6/btrKHUAMBrk/qEJfDf3L8vmpqkf8G6zRx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAARq6%2FbtrKHUAMBrk%2FqEJfDf3L8vmpqkf8G6zRx1%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;773&quot; height=&quot;681&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;681&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0ab763df-6022-4456-bc60-c1ac4711dbc1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-daa2535a-51a7-4bd9-a482-4898914ce552&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;현재의 상황은 앞의이미지와 같습니다. 두 번째 노드에선 account new를 수행하지 않았기 때문에 해당 노드가 관리하고 있는 keystore 파일은 존재하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-abb36af0-3a7b-4a44-ad55-4ea3c4467586&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-05bd5720-d674-4bdb-9c23-0a7bd2baea03&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 네트워크 연결&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-1ab64f4f-7f92-4497-8bb1-4c4579c24d40&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 만든 두 개의 노드를 연결하기 위해 빨간색, 파란색으로 표시한 두 번째 박스를 보면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;enode&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 보일것입니다. enode는 노드간 연결하기 위한 식별자로 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1851d966-c93d-47d2-bc59-414510f8920d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-201980cd-c526-4039-980a-51b854553cb2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;첫 번째 노드&lt;/b&gt;&lt;/span&gt;&lt;span&gt;의 &lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;enode&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 복사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4d84dcd1-44ee-4937-9ec8-b567b7ee5f96&quot;&gt;
&lt;pre id=&quot;code_1661587464165&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enode://3d161a305a562575f7ca7a3e99dc5254556fc126098e4128644fb580e3b83fd6fc5ad27ef721428d1473115442c7150da15c6f7a2ff08edd7623ca9dd0e192ba@127.0.0.1:30303?discport=0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ce0d5c40-53b2-49ea-86dc-78f9d716a7ce&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-436d3aac-3a8c-4c90-be45-9498d315453f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0078cb;&quot;&gt;&lt;b&gt;두 번째 노드&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에서&lt;/span&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt; 첫 번째 노드의 enode&lt;/b&gt;&lt;/span&gt;&lt;span&gt;로 연결 요청을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-838d2cde-3e08-4397-aa40-b8b11d9b0fb9&quot;&gt;
&lt;pre id=&quot;code_1661587474174&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; admin.addPeer('enode://3d161a305a562575f7ca7a3e99dc5254556fc126098e4128644fb580e3b83fd6fc5ad27ef721428d1473115442c7150da15c6f7a2ff08edd7623ca9dd0e192ba@127.0.0.1:30303?discport=0')&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f2bd9121-388c-4017-b73e-dcbfc1c0ea3c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;93&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctGK55/btrKGxGBheN/uSP5BRNQ1jEKgk4utVpgO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctGK55/btrKGxGBheN/uSP5BRNQ1jEKgk4utVpgO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctGK55/btrKGxGBheN/uSP5BRNQ1jEKgk4utVpgO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctGK55%2FbtrKGxGBheN%2FuSP5BRNQ1jEKgk4utVpgO0%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;773&quot; height=&quot;93&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;93&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a09890cb-9ec1-48c4-9570-eaf66bcf7f2f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c0be1f1b-17bc-4b00-a0ba-9547fa1b6dde&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-ce7c5eda-78e5-4dae-8169-e5dc31ad9292&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 연결확인&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-72b4c924-3cb4-4d38-9412-e0ee2b6c6ea5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 명령어를 통해 해당 노드가 연결된 피어를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eb709700-9b76-45bf-814f-17d1d4ba8420&quot;&gt;
&lt;pre id=&quot;code_1661587484229&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; admin.peers&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-37583100-90ee-433c-81cf-3aedb32f229b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEKb2d/btrKJ4Qq5Bs/Aw1Hr2NCwBiAPxmrMY16w0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEKb2d/btrKJ4Qq5Bs/Aw1Hr2NCwBiAPxmrMY16w0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEKb2d/btrKJ4Qq5Bs/Aw1Hr2NCwBiAPxmrMY16w0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEKb2d%2FbtrKJ4Qq5Bs%2FAw1Hr2NCwBiAPxmrMY16w0%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;773&quot; height=&quot;453&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;453&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8589cc48-85e4-4f4f-a0ef-1c4a16e31e98&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e1080e11-b2c6-47ee-9ab1-956a0ce1fa3f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c66b2ecf-108c-440c-aa6c-90fa6e2ee4b0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그냥 단순히 연결된 피어숫자 및 연결가능 상태를 확인하기 위해선 다음 명령어를 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5afc803f-9da2-49d3-90e4-49a31f7907e2&quot;&gt;
&lt;pre id=&quot;code_1661587490909&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; net
{
  listening: true,
  peerCount: 1,
  version: &quot;10&quot;,
  getListening: function(callback),
  getPeerCount: function(callback),
  getVersion: function(callback)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-24539002-8a50-4cd8-9b7a-218c575af4a2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-ab8fe99f-296f-4ccd-9deb-afe47986ea42&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;listening&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 연결 가능상태를 알려줍니다. true는 연결가능 상태입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9d2feeb9-8aef-484d-bfd8-3f5d70b96148&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;peerCount&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 해당 노드가 연결된 피어수 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-201211a7-5513-4864-9177-c9ecdc7a17df&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;version&lt;/b&gt;&lt;/span&gt;&lt;span&gt;이 일치한 노드만 연결할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b9c5b416-a218-4a3a-a679-641fd91428e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;SE-60c3c223-d217-4259-b774-e0ed990e9290&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;5. 동작 테스트&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p id=&quot;SE-c242d71d-abbb-4b31-b694-3f93c8d44da0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마지막으로 우리가 만든 네트워크의 노드들이 잘 동작하는지 테스트해야 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-10c1623d-6583-4295-b653-0733fb1805d4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5a3bc7f2-cf68-416e-886b-55c38654afac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그런데 무엇을 테스트해야할까요?&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7cc24d5e-ec06-4871-97e0-d9c5a2a1282d&quot;&gt;
&lt;pre id=&quot;code_1661587501509&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. 트랜잭션 생성/전파
2. 블록 생성/전파
3. 동일한 state를 가지고 있는지&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-51ef30a9-4b7c-4a20-ba0e-6c475f4d239e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-cf5f1aab-f225-40a5-945f-3cd708bb0e15&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 트랜잭션 생성/전파&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-31d01118-f5ad-421a-afd3-7517edda2660&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장먼저 확인해 볼 것은 트랜잭션을 생성하고 전파하는 부분입니다. 트랜잭션이 생성되면 해당 트랜잭션이 블록에 포함되기 전의 상태를 pending 상태라고 합니다. 즉, pending 상태의 트랜잭션 전파가 잘 이루어 지는지까지 테스트해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6ab05c9b-0ef9-4d5f-8066-e6ddf104c837&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d1d482d6-83e0-44cb-8e99-6b582cf43ba1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;geth의 경우 keystore 파일에 lock이 걸려있기 때문에 트랜잭션을 발생하기 전에 unlock해야 합니다. 해당 명령어는 unlock하고자 하는 keystore 파일이 있는 노드에서 진행해야 하기 때문에 node1에서 진행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-36ee4438-58ea-4511-a389-cd2e736653e4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-de150761-4639-4788-9141-75534cf321b5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661587525678&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;  personal.unlockAccount(eth.accounts[0])
Unlock account 0x04deb80cc89c42d8148312cfc16e1579e4af7291
Passphrase: 
true&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-c74e846b-0a2c-4604-b41e-76277f8c5a41&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션을 발생하는 명령어는 다음과 같습니다. (트랜잭션을 발생하는 방법은 여러가지 있습니다)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d1324667-8165-4449-a841-e2078315bf8c&quot;&gt;
&lt;pre id=&quot;code_1661587532509&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;eth.sendTransaction({from: 발신자, to: 수신자, value: 금액(단위 wei)})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c2284ffa-33ae-4bba-b37c-673ac12db050&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e0e8c77b-3663-4c14-a214-5d34dfe54df3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661587538181&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: 123})

WARN [02-16|22:23:00.390] Caller gas above allowance, capping      requested=125222772 cap=25000000
INFO [02-16|22:23:00.390] Submitted transaction                    fullhash=0x438f1f0bcba2bfafa76b6c80d5838648d3b79d6f2bfe7b0920393f061592fca7 recipient=0x2c08FF6B5cfaA09BBe87c2B16B0f3A234901917E
&quot;0x438f1f0bcba2bfafa76b6c80d5838648d3b79d6f2bfe7b0920393f061592fca7&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-4c0ca6bc-b184-4f83-a02e-1bf968d5a9f6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 결과처럼 나온다면 트랜잭션이 정상적으로 발생된 것 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e1f0d177-65bc-42d7-83c1-2a6786d3b9ae&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6992f4f1-2d8e-48e7-9b00-17506f93d87e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;발생된 트랜잭션을 확인하기 위해 다음 명령어를 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0c6823d1-1ae8-4d21-969f-d169d125aefd&quot;&gt;
&lt;pre id=&quot;code_1661587544117&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;eth.pendingTransactions&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bd9c2cf3-49b3-4c77-934a-21babb319d37&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUtpNo/btrKF0oGkGq/s4a4ZzxbPciYcVP2kYJzH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUtpNo/btrKF0oGkGq/s4a4ZzxbPciYcVP2kYJzH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUtpNo/btrKF0oGkGq/s4a4ZzxbPciYcVP2kYJzH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUtpNo%2FbtrKF0oGkGq%2Fs4a4ZzxbPciYcVP2kYJzH0%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;736&quot; height=&quot;690&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-96dc322b-a6a8-404f-b4db-d83479bf6dfe&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-517a0ad8-d4c7-4113-a1da-38b627eaf9e2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째 노드에서 발생한 트랜잭션이 두 번째 노드에 잘 전파된 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2e1a4dd0-c6aa-43f6-9f64-71897b4db100&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-672e3d02-d5d8-494a-9fe2-c401e9817224&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a50f3159-aaa5-4e58-91ed-a68f529ddce8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서부터 앞에서 실수한 부분이 있어 주소값이 앞과 상이하게 표시될 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a426ec3-3f79-418b-93a0-13a35630e96a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b96ce725-0638-4e21-af46-b734c9b8922c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(여기서 from, to가 앞에서 생성안 주소랑 달라지는데 글을 쓰면서 구동을 하다보니 실수해서 다시 처음부터 진행한 덕에 주소값이 다르게 표시됩니다)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3707ce25-b474-4f6e-bad0-6c99e5790ab1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-0739328a-8b9e-4a7f-b121-8000f4240f28&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 블록생성 전파&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-e72246bf-aa68-4646-80e0-cc1d2f21627a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;블록생성의 경우 아무 노드에서나 다음 명령어를 수행하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ed7c11c2-6540-49a2-9951-ff95f41f605f&quot;&gt;
&lt;pre id=&quot;code_1661587562685&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; miner.start()
&amp;gt; miner.stop()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-160ff437-0484-4e41-b126-213c235601b4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-886a928c-88e1-41ea-8de9-e339ded47154&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;저는 첫 번째 노드에서 블록을 생성했지만 두 번째 노드에서 블록생성을 시도하겠습니다. 그리고 앞에서 생성한 트랜잭션 해쉬값은 잘 가지고 있습니다. 추후에 블록에 잘 들어갔는지 확인하는 용도로 사용할 것 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3f5f0fcf-8378-483a-8039-1847a79e19d0&quot;&gt;
&lt;pre id=&quot;code_1661587567197&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;0x438f1f0bcba2bfafa76b6c80d5838648d3b79d6f2bfe7b0920393f061592fca7&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e4b12f9f-154b-40a5-b841-b466a7cfb4b4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-4b10b17b-a8d1-4d0d-8371-3142a1f39e19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;아직 블록에 포함되지 않았기 때문에 blockHash와 blockNumber가 null이 저장되있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-36309431-313e-49eb-924e-19f167a808cd&quot;&gt;
&lt;pre id=&quot;code_1661587575724&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.getTransaction('0x438f1f0bcba2bfafa76b6c80d5838648d3b79d6f2bfe7b0920393f061592fca7')
{
  blockHash: null,
  blockNumber: null,
  from: &quot;0x598373c741d15d4c6b993288fe94e92231355d12&quot;,
  gas: 21000,
  gasPrice: 21000,
  hash: &quot;0x438f1f0bcba2bfafa76b6c80d5838648d3b79d6f2bfe7b0920393f061592fca7&quot;,
  input: &quot;0x&quot;,
  nonce: 8,
  r: &quot;0x95664b35aa1cc1945564a57baa624f519c10d236b579aecc52df8a9503fa2946&quot;,
  s: &quot;0x192aa1271dfcae8d44dcc3ba7ec50a7e8bc5139ebbc2e777002e2bc7eed4f2a&quot;,
  to: &quot;0x2c08ff6b5cfaa09bbe87c2b16b0f3a234901917e&quot;,
  transactionIndex: null,
  v: &quot;0x37&quot;,
  value: 123
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ed97f594-792d-4184-a3f4-a86c16616c16&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqeMG/btrKLfjTsp6/58MTg23hOWtmW2SeKDXMDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqeMG/btrKLfjTsp6/58MTg23hOWtmW2SeKDXMDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqeMG/btrKLfjTsp6/58MTg23hOWtmW2SeKDXMDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrqeMG%2FbtrKLfjTsp6%2F58MTg23hOWtmW2SeKDXMDk%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;734&quot; height=&quot;688&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3d8de407-910a-430c-b9b5-42bccf444054&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9b6db6e2-40da-4c0b-9314-562c2706c686&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;저는 두 번째 노드인 아래 노드에서 POW 알고리즘을 동작했습니다. POW 결과에 따라 생성된 블록을 연결된 첫 번째 노드로 전파를 합니다. miner.stop()을 이용하여 마이닝을 멈춰줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-265b1ec9-4539-49d9-956c-61a982688464&quot;&gt;
&lt;pre id=&quot;code_1661587582798&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.blockNumber&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-358956ad-576e-4151-90bf-1a963b51fcca&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lYLOe/btrKGw8LJcS/wOTNngbawX04byns3m91xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYLOe/btrKGw8LJcS/wOTNngbawX04byns3m91xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYLOe/btrKGw8LJcS/wOTNngbawX04byns3m91xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYLOe%2FbtrKGw8LJcS%2FwOTNngbawX04byns3m91xk%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;734&quot; height=&quot;271&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5b2201ba-8de2-48d1-9617-1d9aa75beb87&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;블록갯수 확인&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bfd1d21c-7908-4c7f-9f6c-f8a0e532cbac&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-15602660-4fb7-4627-8567-fb38340793b1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661587589413&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.getTransaction('0x438f1f0bcba2bfafa76b6c80d5838648d3b79d6f2bfe7b0920393f061592fca7')
{
  blockHash: &quot;0x560ed0ae33404daeb8c23da288532fba46220a9f13c3c0380d4be2061887d09e&quot;,
  blockNumber: 71,
  from: &quot;0x598373c741d15d4c6b993288fe94e92231355d12&quot;,
  gas: 21000,
  gasPrice: 21000,
  hash: &quot;0x438f1f0bcba2bfafa76b6c80d5838648d3b79d6f2bfe7b0920393f061592fca7&quot;,
  input: &quot;0x&quot;,
  nonce: 8,
  r: &quot;0x95664b35aa1cc1945564a57baa624f519c10d236b579aecc52df8a9503fa2946&quot;,
  s: &quot;0x192aa1271dfcae8d44dcc3ba7ec50a7e8bc5139ebbc2e777002e2bc7eed4f2a&quot;,
  to: &quot;0x2c08ff6b5cfaa09bbe87c2b16b0f3a234901917e&quot;,
  transactionIndex: 0,
  v: &quot;0x37&quot;,
  value: 123
}
&amp;gt; eth.pendingTransactions
[]&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-429dd043-fe21-4989-aa26-9ff4030f3d30&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;트랜잭션이 블록에 포함된 정보와 pending 상태의 트랜잭션이 비어져있는 모습을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0d9d8f83-7906-43c1-95a9-5cd0b0b8a834&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-d22a052a-66e8-4e57-abe7-4fe10a45d0cd&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; state 확인&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p id=&quot;SE-3c87541a-5867-400b-969b-763ad69448a1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞에서 블록, 트랜잭션 상태가 동일하게 공유된 모습을 확인했습니다. 하지만 가장 중요한 것은 주소마다 보유한 이더리움이 같은지 확인을 해야합니다. 첫 번째 노드에서 관리중인 keystore의 주소값을 조회하기 위해 eth.accounts를 이용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5f6bc50f-63ac-4ae2-96ef-e374a874569f&quot;&gt;
&lt;pre id=&quot;code_1661587601500&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.accounts
[&quot;0x598373c741d15d4c6b993288fe94e92231355d12&quot;, &quot;0x2c08ff6b5cfaa09bbe87c2b16b0f3a234901917e&quot;, &quot;0xffe3aa6829730ded2c9f8a8ef1e72303f628c9b3&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1db3c46d-6f3e-46c0-b6e0-adf0850e09aa&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-1e205e01-e5f3-4284-8e52-a8d24b3c07c5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 각각의 이더잔액을 조회하기 위해 eth.getBalance()를 이용합니다,&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-efbd4e8e-17ab-4cbf-9d4a-83dd1e7b5cd8&quot;&gt;
&lt;pre id=&quot;code_1661587606148&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.getBalance(주소)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d528d37a-3eee-4871-862d-88bdbc37b379&quot;&gt;
&lt;pre id=&quot;code_1661587611380&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.getBalance('0x598373c741d15d4c6b993288fe94e92231355d12')
&amp;gt; eth.getBalance('0x2c08ff6b5cfaa09bbe87c2b16b0f3a234901917e')
&amp;gt; eth.getBalance('0xffe3aa6829730ded2c9f8a8ef1e72303f628c9b3')&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f7f9323-88cd-410f-85b3-3907aa0261c3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-38c2de14-ef4a-4bd7-9fd8-8c029f01a1b4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;첫 번째, 두 번째 노드에서 실행하여 잔액을 확인합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1657c6e0-f815-4765-9537-85247abffa9f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FUrsj/btrKJ5hxixb/iNxbXYifO58yR8y6thEzuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FUrsj/btrKJ5hxixb/iNxbXYifO58yR8y6thEzuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FUrsj/btrKJ5hxixb/iNxbXYifO58yR8y6thEzuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFUrsj%2FbtrKJ5hxixb%2FiNxbXYifO58yR8y6thEzuk%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;733&quot; height=&quot;326&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-71be9000-8dc4-4421-93e1-6fe1a3719216&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-324d0fa8-35b2-443d-b51e-e77cc40b115a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 Looking for peers는 노드를 실행할 때 --nodiscovery 옵션을 주지 않았기 때문에 주기적으로 연결할 노드를 탐색하고 있는 로그입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-43f24478-bce7-43a2-bf83-ca24ceab51c6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5e41f9fb-9281-4cc4-8032-fd06db0c56ea&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 시간엔 private한 형태로 네트워크 구축하는 방법을 알아보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-186a0f1f-da36-463f-9189-49139ac6d242&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9b802574-08db-4436-bdb2-fdccead460b4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 시간엔 여기서 다루지 않은 개념적인 내용과 우리가 만든 private 네트워크망에서 노드 모니터링을 연동해보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;a href=&quot;https://ethstats.net/&quot;&gt;https://ethstats.net/&lt;/a&gt;&lt;/p&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>Ethereum</category>
      <category>geth</category>
      <category>private</category>
      <category>네트워크</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/67</guid>
      <comments>https://meongae.tistory.com/67#entry67comment</comments>
      <pubDate>Sat, 27 Aug 2022 17:07:16 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] mnemonic 생성, privatekey 복구와 계층적 구조의 원리</title>
      <link>https://meongae.tistory.com/66</link>
      <description>&lt;div id=&quot;SE-fd6f6da9-8d09-402e-8cc7-e2cfe44b34a3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-1466ddcd-ef3c-4bc6-9855-a0a79e92e7cb&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 라이브러리 설치&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fc0077fd-e9b0-48fc-85c5-0aa707382a68&quot;&gt;
&lt;pre id=&quot;code_1661586791089&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save bip39 $ npm install --save ethereumjs-wallet&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-61e1b199-a85c-4eb3-816b-9dfe97807dea&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-467f47de-a85b-4915-bb7e-463f59839c10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-33562645-5f77-4333-8b9c-45f2f4169b26&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; mnemonic 생성&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a5a3fef9-3e9b-4c31-91ff-9f8fddf42364&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-298a7dbf-2164-4ab9-a4c7-6963d5352e87&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661586819376&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const bip39 = require(&quot;bip39&quot;);
const mnemonic = bip39.generateMnemonic();
console.log(`mnemonic is : &quot;${mnemonic}&quot;`);&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-46773707-84a8-41b6-9b1b-b6a0ad63d858&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;bip39를 이용하여 mneminic을 생성할 수 있습니다. mnemonic은 12개의 단어로 이루어진 문자열입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7fcf0c10-cafa-42da-92ee-8e23bc05777c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-df554d6d-0ede-4e7d-a519-afebb20ba349&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; privatekey 복구&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-137ca5aa-6986-42e9-8e10-12a50a6cc4f5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bd76ee39-835e-4c77-86bf-6ac7e4454efc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661586828032&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const bip39 = require(&quot;bip39&quot;);
const { hdkey } = require(&quot;ethereumjs-wallet&quot;);

const mnemonic = &quot;good buyer welcome fabric call effort initial vendor surge diesel leader flip&quot;;
(async () =&amp;gt; {

  const seed = await bip39.mnemonicToSeed(mnemonic); // seed === entropy
  const rootKey = hdkey.fromMasterSeed(seed);
  const hardenedKey = rootKey.derivePath(&quot;m/44'/60'/0'/0&quot;);
  const childKey = hardenedKey.deriveChild(0); // 값조정 가능
  const wallet = childKey.getWallet();
  const address = wallet.getAddress();
  const privateKey = wallet.getPrivateKey();
  console.log(`seed is ${seed.toString('hex')}`)
  
  console.log(`======== rootKey =======`)
  console.log(rootKey)

  console.log(`======= childKey =======`)
  console.log(childKey)

  console.log(`======= wallet is =======`)
  console.log(wallet)

  console.log(`address is ${address.toString(&quot;hex&quot;)}`);
  console.log(`privateKey is ${privateKey.toString(&quot;hex&quot;)}`);
})()&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-12e08c35-fd24-44fe-aee9-dce00d32affd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;생성된 mnemonic을 이용하여 privatekey와 address를 생성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7c2dc5c8-87ef-45b4-af48-5d852d677a97&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0e6d02b5-ee87-40eb-87a3-c9fbc4b2c30e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;mnemonic을 이용하면 항상 동일한 privatekey와 address를 생성할 수 있습니다. 정확히 말하면 childrenKey를생성하게 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5b9bf1c6-12af-4f42-9388-0e2b1de23dd2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;mnemonic을 이용하면 128Bits의 seed(entropy)를 생성합니다 seed를 이용하여 masterKey를 생성하며 마스터키를 이용하여 childrenKey 생성이 가능하며 해당 키를 이용하여 public, private key생성이 가능해집니다. 아래 이미지를 참고하면 좀 더 이해가 쉬울겁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a83ea0d4-39a6-4183-9d42-cbb627d5a40a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-240e1297-1086-42dc-9add-1bdc3d4acde7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cC0F9N/btrKGQ6ZKQV/Epka81gOlvB6PRc4hst9A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cC0F9N/btrKGQ6ZKQV/Epka81gOlvB6PRc4hst9A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cC0F9N/btrKGQ6ZKQV/Epka81gOlvB6PRc4hst9A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcC0F9N%2FbtrKGQ6ZKQV%2FEpka81gOlvB6PRc4hst9A0%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;773&quot; height=&quot;476&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4af1ccb5-44c3-4ff9-9638-72588649fec5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-65ca76eb-09ba-480d-9d63-3e28dd8b3e36&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4699c1a2-e509-406a-a016-611e0643abd1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;masterKey 또는 childrenKey의 derivePath를 이용하면 privateKey와 publicKey생성이 가능합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-333578b0-fa27-4359-b1cd-bef08e6e384d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 구조를 &lt;/span&gt;&lt;span&gt;&lt;b&gt;계층구조&lt;/b&gt;&lt;/span&gt;&lt;span&gt;라고 합니다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5a1a80f6-021a-4f23-9ff9-448dbb8ae5b0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1f44abd8-fa41-4c1b-b851-5c20a1d165df&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661586836744&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let hardenedKey1 = childKey.derivePath(&quot;m/44'/60'/0'/0&quot;);
let childKey1 = hardenedKey1.deriveChild(0)
console.log(childKey1.getWallet().getAddress().toString('hex'))
console.log(childKey1.getWallet().getPrivateKey().toString('hex'))&lt;/code&gt;&lt;/pre&gt;
&lt;p id=&quot;SE-dda36213-1adb-4015-9adb-47b8228f3839&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 코드처럼 앞에서 생성한 childrenKey를 이용하여 또다시 childrenKey 생성이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8978942e-e443-424c-a697-d5d3d45b3a02&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;hr class=&quot;se-hr&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1389c5c2-d820-4246-9092-51ab4e810352&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-748539c6-e594-4ff9-ac84-5d61cd187134&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 한가지 의문점이 있을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-862daa04-7405-459b-8ece-1ca9fcb4958a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e05f5b87-8abc-44e6-91f4-d2ccd97d7206&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;바로 derivePath인데 해당 구문은 다음 이미지를 참조하면 이해할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7d897045-0a58-4378-a9c2-06a3c0fde3e9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;403&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIgo3E/btrKF7g3JEw/CCkeqnSkYnsg2IQuFQJ2r0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIgo3E/btrKF7g3JEw/CCkeqnSkYnsg2IQuFQJ2r0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIgo3E/btrKF7g3JEw/CCkeqnSkYnsg2IQuFQJ2r0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIgo3E%2FbtrKF7g3JEw%2FCCkeqnSkYnsg2IQuFQJ2r0%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;677&quot; height=&quot;403&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;403&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-54d3526b-5b17-43a8-944e-730069e3c953&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;m &lt;span style=&quot;color: #a77f71;&quot;&gt;/&lt;/span&gt; purpose&lt;span style=&quot;color: #60911b;&quot;&gt;' / coin_type'&lt;/span&gt; &lt;span style=&quot;color: #a77f71;&quot;&gt;/&lt;/span&gt; account' &lt;span style=&quot;color: #a77f71;&quot;&gt;/&lt;/span&gt; change &lt;span style=&quot;color: #a77f71;&quot;&gt;/&lt;/span&gt; address_index&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a6710600-e87e-4f49-8d9a-e8ba5db116af&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5bc803a8-9853-4126-bb20-eaa197d77f95&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움은 coin_type이 60입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1db6898c-0577-4fb9-be48-0fbe93caa022&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-aacafeda-3152-47f3-bfb7-84eaf591fea4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;coin_type의 자세한 정보는 아래 링크에서 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c542dcb7-2313-4d28-9a52-faeaea969f08&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c1322568-b35c-4397-9211-b333ffffd929&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/satoshilabs/slips/blob/master/slip-0044.md&quot;&gt;https://github.com/satoshilabs/slips/blob/master/slip-0044.md&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7e320a84-e3a9-41c4-99d5-0a8da2c486ee&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bauRqs/btrKFSLfv1O/j7VLUCeRMMTJ9prTr0ZgUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bauRqs/btrKFSLfv1O/j7VLUCeRMMTJ9prTr0ZgUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bauRqs/btrKFSLfv1O/j7VLUCeRMMTJ9prTr0ZgUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbauRqs%2FbtrKFSLfv1O%2Fj7VLUCeRMMTJ9prTr0ZgUk%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;500&quot; height=&quot;300&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;a href=&quot;https://github.com/satoshilabs/slips/blob/master/slip-0044.md&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7c0fe123-d19f-4789-8c72-08b0d0f4448c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5b593b8a-2181-42a5-990c-0a54e4532123&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-59955681-d8f3-413f-972b-40bdf676cee9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;샘플 코드는 깃허브에서 확인가능 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ed4988bf-c231-4b83-84f7-cd1af176abba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/pjt3591oo/ether-mnemonic&quot;&gt;https://github.com/pjt3591oo/ether-mnemonic&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5c1213c5-b213-4240-a155-ce05aeb3a5f0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d4K8CO/btrKHUU24tp/oyn3Qm1OO9gbdtLtOBSTw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d4K8CO/btrKHUU24tp/oyn3Qm1OO9gbdtLtOBSTw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d4K8CO/btrKHUU24tp/oyn3Qm1OO9gbdtLtOBSTw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd4K8CO%2FbtrKHUU24tp%2Foyn3Qm1OO9gbdtLtOBSTw0%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;500&quot; height=&quot;300&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-394ae430-8dd3-4b4d-b738-f41664b9da4d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>bip39</category>
      <category>childrenkey</category>
      <category>masterkey</category>
      <category>mnemonic</category>
      <category>니모닉</category>
      <category>블록체인</category>
      <category>월랫</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/66</guid>
      <comments>https://meongae.tistory.com/66#entry66comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:54:29 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] privatekey를 이용하여 address 복구, transaction 발생</title>
      <link>https://meongae.tistory.com/65</link>
      <description>&lt;div id=&quot;SE-e49d90f9-a90a-4f1b-b9c8-34642b674fa3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c6b28abc-1fbf-4b0c-98df-83ea0031b96a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;privateKeyToAccount()를 이용하면 privatekey를 이용하여 account를 가져올 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8f75df61-36aa-4eec-bc50-3fdcf7e239be&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c0678bda-1173-42a7-9427-6bbd28859b20&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661586573801&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let Web3 = require('web3')
let web3 = new Web3(new Web3.providers.HttpProvider('https://ropsten.infura.io'));

let PK = &quot;0x1076f9a014620c526eaf424cad97755a8d5c1a492f2637731f56975d30805db6&quot;

let account = web3.eth.accounts.privateKeyToAccount(PK)
console.log(account)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;SE-611435cd-b6bf-4f43-8da7-a3df4698a2c6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 실행결과&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-333c0a9c-2644-42c7-aa5b-e9addac874e5&quot;&gt;
&lt;pre id=&quot;code_1661586651984&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ address: '0x31bF95273C33C9042da801580F6d54a6f11b3CfE',
  privateKey:
   '0x1076f9a014620c526eaf424cad97755a8d5c1a492f2637731f56975d30805db6',
  signTransaction: [Function: signTransaction],
  sign: [Function: sign],
  encrypt: [Function: encrypt] }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b02e60c2-cc11-4966-8207-244f6d960abd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-33216055-eb3e-4c09-a837-9e4e2e9e77f0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가져온 account에서 encrypt를 이용하면 keystore를 만들 수 있고, signTransactio을 이용하면 트랜잭션에 서명하여 rawTransaction을 만들 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4be16d0b-c618-4702-98f8-25182fa2602c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;SE-e3df86e8-fb91-417c-8943-34ea18e002e3&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; sample&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-292ce230-eecd-439f-8ce4-6da18e2dcf7b&quot;&gt;
&lt;pre id=&quot;code_1661586699464&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let Web3 = require('web3')
let web3 = new Web3(new Web3.providers.HttpProvider('https://ropsten.infura.io'));

/*
  web3.utils.toWei(1, 'ether')  : 1ETH        =&amp;gt; 1 * 10 ^ 18
  web3.utils.fromWei(1, 'ether'): 1 * 10 ^ 18 =&amp;gt; 1ETH
*/

(async () =&amp;gt; {
  let EOA1 = &quot;0x31bF95273C33C9042da801580F6d54a6f11b3CfE&quot;
  let PK = &quot;0x1076f9a014620c526eaf424cad97755a8d5c1a492f2637731f56975d30805db6&quot;
  let EOA2 = &quot;0x22C353816541d2437dd9Aa673Be0de07d869df6B&quot;

  let eoa1_nonce = await web3.eth.getTransactionCount(EOA1, &quot;pending&quot;)
  let balance = await web3.eth.getBalance(EOA1)
  
  console.log(eoa1_nonce)
  console.log(balance)
  console.log(web3.utils.toWei(&quot;0.1&quot;, 'ether'))
  console.log(web3.utils.toWei(&quot;21&quot;, 'Gwei'))

  let txParam = {
    nonce: eoa1_nonce,
    from: EOA1,
    to: EOA2,
    value: web3.utils.toHex(web3.utils.toWei(&quot;0.1&quot;, 'ether')), // 0.1 이더
    gasPrice: web3.utils.toHex(web3.utils.toWei(&quot;21&quot;, 'Gwei')), // 가스 가격
    gasLimit: web3.utils.toHex(300000), // 가스 최대 사용량
  }

  let account = web3.eth.accounts.privateKeyToAccount(PK)
  let signedTx = await account.signTransaction(txParam)

  let txInfo = await web3.eth.sendSignedTransaction(signedTx.rawTransaction, (err, txHash) =&amp;gt; {
    if (err) {
      console.log('========== transaction 발생 중 에러 ===========')  
      return
    }
    console.log('========== transaction 발생 ===========')
    console.log(txHash)
  })

  console.log('========== transaction 처리완료 ===========')
  console.log(txInfo)
})()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>blockchain</category>
      <category>Ethereum</category>
      <category>transaction</category>
      <category>web3</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <category>트랜잭션</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/65</guid>
      <comments>https://meongae.tistory.com/65#entry65comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:52:00 +0900</pubDate>
    </item>
    <item>
      <title>[블록체인] 블록체인 시스템은 어떻게 구축할까 1편 - exchange, wallet, payment에서 transaction 취급방법</title>
      <link>https://meongae.tistory.com/64</link>
      <description>&lt;div id=&quot;SE-403c206d-2e1e-49bb-b245-b1c0db4c1d70&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-a05ddd1e-6701-4436-a737-946babff7cba&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;▶ 서론&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-72802773-fa55-4512-a0b3-9c926fb39968&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-563e41a9-09f5-4d57-8b6c-dbecc5da0d92&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;블록체인의 가장 큰 단점은 처리속도가 느리다는 점 입니다!! &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3dd1193f-9170-4106-958f-3da298ba6c70&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-56270e6f-9003-40c0-8bf5-ff19db6f9a0f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처리속도가 느리다는건 transaction을 처리하는데 소요 시간이 든다는 점 입니다. 이러한 특징 때문에 블록체인 기반 어플리케이션은 transaction 처리를 많이 고민해야 합니다. 또한, 모든 어플리케이션이 transaction을 같은 형태로 처리하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-11fee906-c58d-4ab1-a049-d47727ea6d88&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c5b5b75f-6298-41b1-ac00-0eebe9262655&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;블록체인 기반의 어플리케이션을 만들게 되면, 블록체인과 데이터베이스의 동기화가 중요합니다. 그렇기 때문에 시스템 특징에 따라 transaction 관리방법을 달리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d916aa9e-f830-46b1-8cf8-dfd236d6e2d0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4a0face8-7ca7-4849-8a6f-d2cf2edbffc4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;필자는 블록체인 기반의 유통 시스템, 평가 시스템 등 다양한 시스템을 구축하면서 transaction 처리 방법에 대해 많은 연구와 고민을 하였으며, 이번글에서는 큰 차별점을 가진 &lt;/span&gt;&lt;span style=&quot;color: #0095e9;&quot;&gt;&lt;b&gt;거래소,&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #0095e9;&quot;&gt;&lt;b&gt;지갑,&lt;/b&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #0095e9;&quot;&gt;&lt;b&gt;암호화폐 기반 결제&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 시스템의 transaction 처리 방법을 소개합니다. 또한 해당 시스템의 기본적인 구조도 함께 소개합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-fe4e5298-23ac-4712-80b6-11d1a92dab19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;s&gt;( 참고로 필자는 현재 거래소와 암호화폐기반 결제 시스템 및 지갑을 개발하고 있습니다.)&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-67800294-cee9-4188-81a6-ddb7780d2615&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e86435d2-8097-4e92-b293-f806ab5987d7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-63af0657-f34b-4704-8287-4ed41097d15c&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;● &lt;b&gt;1. 거래소(exchange)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9d5c15a7-40ae-4318-91d0-0af8e067f3fd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-85890c1d-fee0-4064-9312-68bdac82aa98&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장먼저, 거래소 시스템에서 transaction을 어떻게 관리하는지 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5c1e5be8-f1bb-4388-afef-176acec03f71&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;거래소는 발생된 모든 거래 내역은 블록체인에 저장하지 않습니다. 거래소에서 대표적인 기능을 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f1e5d5f5-9a51-4334-af34-835eeea90f60&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0e5e01af-3486-407d-84c7-d581cb9e34ca&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-becdffbb-3599-446d-a525-de71c066d8dd&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; &lt;b&gt;1.1 거래소 대표기능&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-87389247-9a2b-462f-a735-17e493f681fc&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjKDbh/btrKJ6U2nDJ/HQ94U4vOqiXAP5xaeIs0f0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjKDbh/btrKJ6U2nDJ/HQ94U4vOqiXAP5xaeIs0f0/img.png&quot; data-alt=&quot;[그림 1.1] 거래 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjKDbh/btrKJ6U2nDJ/HQ94U4vOqiXAP5xaeIs0f0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjKDbh%2FbtrKJ6U2nDJ%2FHQ94U4vOqiXAP5xaeIs0f0%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;773&quot; height=&quot;474&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.1] 거래 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-102fcc7f-514d-4a09-942a-04e9cf574d80&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBb5IP/btrKK9KJ0qY/dKxjunq4jntKft4TXcfFnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBb5IP/btrKK9KJ0qY/dKxjunq4jntKft4TXcfFnk/img.png&quot; data-alt=&quot;[그림 1.2] 출금 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBb5IP/btrKK9KJ0qY/dKxjunq4jntKft4TXcfFnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBb5IP%2FbtrKK9KJ0qY%2FdKxjunq4jntKft4TXcfFnk%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;773&quot; height=&quot;442&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.2] 출금 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-921fb114-200f-4a18-bb3b-d6ab5004bb92&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHQPQq/btrKIqMXRL9/dkdohlLeXVQN5EmaqvKSjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHQPQq/btrKIqMXRL9/dkdohlLeXVQN5EmaqvKSjK/img.png&quot; data-alt=&quot;[그림 1.3] 입금 페이지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHQPQq/btrKIqMXRL9/dkdohlLeXVQN5EmaqvKSjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHQPQq%2FbtrKIqMXRL9%2FdkdohlLeXVQN5EmaqvKSjK%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;773&quot; height=&quot;442&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.3] 입금 페이지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-5c24b960-7aae-4816-895b-2aefb43d5d9d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2afbcd80-46a9-4a83-a39f-a33240f673c2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;1. 코인/토큰 매매 등록하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-42ae2c6c-1825-4967-8032-797409248b6d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;2. 코인/원화 입금하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3a18417a-d920-43f7-b163-93a55f84151b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;3. 코인/원화 출금하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-801b08c7-b07c-4f2e-82a8-61bcb9b05af0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-898a208e-fa4f-4190-b767-aeed24672594&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;거래소의 대표적인 기능 3가지 입니다. 여기서 3번만 블록체인에 저장합니다. 하지만 특정 상황에 대해서만 블록체인에 transaction을 관리하고 일반적으로는 데이터베이스로만 관리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8a9c40fb-1833-4e9e-a279-a7d309d4a400&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-73adbc4c-87c6-4e0b-be58-33e301f09385&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-31e5a557-4b1e-41da-a798-4bc886a05286&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; &lt;b&gt;1.2 코인/토큰 매매 등록하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a230bf25-e765-40d7-a367-dcc435a16844&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-03e7a877-5736-496d-9d2f-b2f9a5bbf9ac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;거래소에서 가장 핵심 기능인 매매 기능을 알아보겠습니다. 사용자는 보유 원화/코인/토큰을 이용하여 구매, 판매등록을 합니다. 사용자가 보유한 원화/코인/토큰은 해당 거래소 시스템에서 데이터베이스로 관리합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-936eb7a1-b29c-4b53-b1ca-f4075b8d4268&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7a91c7bd-6659-4569-bf27-0229ffc40ea3&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dMNgI2/btrKGoQnuox/LTwBuGJpzqzMQuKz3yHhSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dMNgI2/btrKGoQnuox/LTwBuGJpzqzMQuKz3yHhSK/img.png&quot; data-alt=&quot;[그림 1.4] 데이터 베이스 - balance관리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dMNgI2/btrKGoQnuox/LTwBuGJpzqzMQuKz3yHhSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdMNgI2%2FbtrKGoQnuox%2FLTwBuGJpzqzMQuKz3yHhSK%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;546&quot; height=&quot;312&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.4] 데이터 베이스 - balance관리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ccf80e60-f680-4de7-b9fe-c85dbb0f1b7b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c909ef74-3135-4d10-8104-e83000b8b814&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;유저가 매매 등록을 하면 balanceTable에서 매매한 만큼 차감을 합니다. 그다음 매칭을 위해 해당 내역을 테이블에 저장합니다. 여기서 매매 등록행위를 오더(order)를 등록한다고 표현합니다. 등록된 오더들을 오더북(orderBook)이라고 부릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-56109af1-293c-4d5a-bdd2-bd9b6ed5898a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-03f3b3b6-2749-4f4b-a577-ce25d7b537f8&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lnlFD/btrKHuCkaUF/yUblSHDTRI5h1aUB65LmJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lnlFD/btrKHuCkaUF/yUblSHDTRI5h1aUB65LmJK/img.png&quot; data-alt=&quot;[그림 1.5] 데이터 베이스 - 오더관리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lnlFD/btrKHuCkaUF/yUblSHDTRI5h1aUB65LmJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlnlFD%2FbtrKHuCkaUF%2FyUblSHDTRI5h1aUB65LmJK%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;546&quot; height=&quot;472&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.5] 데이터 베이스 - 오더관리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a845129c-15e9-4313-9330-5828f8bab23b&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-82cc3f11-76c2-4065-bedd-26d514f607e1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사용자가 오더(매매)를 넣으면 보유중인 원화/코인/토큰을 저장하는 balance 테이블을 업데이트 한 후 orderBook에 해당 주문을 추가합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-aa27c371-29b1-45d6-bef8-60789c998f1e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b2199df4-1040-426e-8477-8fa04a44dd1b&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mg62z/btrKIydb7CZ/Kcr9Kmx3eIU1ywqeqaKDKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mg62z/btrKIydb7CZ/Kcr9Kmx3eIU1ywqeqaKDKK/img.png&quot; data-alt=&quot;[그림 1.6] 데이터 베이스 - 채결 데이터 관리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mg62z/btrKIydb7CZ/Kcr9Kmx3eIU1ywqeqaKDKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmg62z%2FbtrKIydb7CZ%2FKcr9Kmx3eIU1ywqeqaKDKK%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;546&quot; height=&quot;472&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.6] 데이터 베이스 - 채결 데이터 관리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-89641290-1d54-498b-88b5-3e8f05601aec&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a2d8b13e-fb29-4c1a-b607-cc6e6ab5ad14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오더를 받는 서버에서 이제 매칭 서버로 해당 오더를 주게되면 매칭 서버는 해당 오더와 채결할 데이터를 선별하여 채결합니다. 이렇게 되면 orderBook 테이블에서 채결 테이블로 옮기게 됩니다. 이때 누구의 오더와 채결했는지를 저장한 후 채결과 동시에 balanceTable을 업데이트 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4c1e5322-116b-4dff-bf21-77aa231f5f4e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(참고로 이 외에 종가를 저장하는 테이블이나 수수료 처리를 하게 됩니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-91fe4c52-a137-4682-a21e-5bc401c0bd88&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bbc49862-259e-4636-a64c-00e9b321f6f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주문을 넣는 프로세스에는 블록체인에서 transaction을 발생하지 않습니다. tx를 발생할 경우 트래픽이 몰리면 해당 데이터를 빠르게 처리할 수 없기 때문입니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7cfcaf75-a9f1-4842-ac83-27b694e75d08&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff0010;&quot;&gt;&lt;b&gt;(사실 다른 이유가 있지만 이 부분은 기술적인 부분보다 비즈니스 적인 부분이라 언급하지 않겠습니다.)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-255e61e0-2fe2-494c-a276-71e08f66b584&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a7e3b0bb-f3be-42b4-9f35-209fe1781923&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;※ 결론. 매수/매도에서는 transaction을 발생시키지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1ede1323-3f97-44c1-a2d4-7a5e91f64371&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c4c6ba87-b81b-47c5-8f0a-72db8e347c86&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-7707b2ab-1b5a-479f-af18-51fabc63abdd&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; &lt;b&gt;1.3 코인/원화 입/출금하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-05684c1f-e6a9-4c05-b8b9-76854a840756&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-54723997-f517-4160-b30c-ddd0b8a9c211&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;거래소는 직바을 2가지 형태로 관리를 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-63a821b8-0c17-4e50-8a5f-5647efbfe07b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c65cb39f-f5c7-4c3a-830f-d858dc5f7eac&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. 거래소(admin) 지갑&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bb3f85b9-9851-4226-b171-f0f71a69192e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. 사용자(user) 지갑&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-95db1d22-3243-433a-9e49-d5d69f656564&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-257c7807-2cc2-4a80-ade6-fc0bfd55ec12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약, 거래소에서 생성한 지갑에 돈을 입금하면 거래소 시스템에서는 &lt;/span&gt;&lt;span style=&quot;color: #0095e9;&quot;&gt;&lt;b&gt;게더링 서버&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 동작하여 사용자 지갑에 있는 코인 및 토큰을 거래소 지갑으로 옮깁니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-53698a2f-bc19-447e-8de0-449d82358993&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aa398b92-11a7-43d3-a50f-734a8b17c1ff&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uSpXr/btrKIyYy6aV/CuKuuNLn018wnf6ZBKwvjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uSpXr/btrKIyYy6aV/CuKuuNLn018wnf6ZBKwvjK/img.png&quot; data-alt=&quot;[그림 1.7] 게더링 서버&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uSpXr/btrKIyYy6aV/CuKuuNLn018wnf6ZBKwvjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuSpXr%2FbtrKIyYy6aV%2FCuKuuNLn018wnf6ZBKwvjK%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;690&quot; height=&quot;472&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.7] 게더링 서버&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-caccf254-4bc3-42ea-a55b-2fa12991101d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-360f4fa2-7219-432b-9d7e-6a768f2d6b1f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사용자 지갑에 있는 보유 코인/토큰을 거래소 지갑으로 옮긴 후, 사용자 코인량을 관리하는 balance 테이블에 옮긴만큼 증가하여 업데이트 합니다. &lt;/span&gt;&lt;span style=&quot;color: #ff97c1;&quot;&gt;&lt;i&gt;&lt;b&gt;토큰의 경우, 지갑에 돈을 입금하면 자동으로 거래소 지갑으로 옮기는 형태로 개발가능합니다.(이 부분은 따로 개발 방법을 알아보겠습니다.)&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-96a17799-0187-4fbd-9341-b4eb1f7e31b1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ff97c1;&quot;&gt;&lt;i&gt;&lt;b&gt;​&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b2a0247e-58a7-46a5-af77-414df16005c9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그리고 여기서 사용자 지갑 -&amp;gt; 거래소 지갑으로 실제 코인/토큰을 옮겨야 하기 때문에 transaction을 발생합니다. 그렇기 때문에 거래소에서 생성한 지갑으로 입금하면 다수의 transaction이 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a93ee396-7ea5-476c-8c67-76207f29dc86&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3d6dbef1-250c-4c4d-a5f2-31dd32d2bf10&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음으론 출금입니다. 출금을 하게되면 수신자가 거래소에서 관리되고 있는 지갑인지 검사합니다. 거래소에서 관리하는 지갑이면 데이터 베이스만 업데이트 합니다. 하지만 거래소에서 관리중인 지갑이 아니면 거래소(admin) 지갑에서 수신자에게 전송하는 transaction을 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a482a24e-fe83-4994-b539-7a1e8b7dd006&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-24225df7-bef1-4c94-8d38-9a43db071743&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pDcn2/btrKHYXtYco/MaNe1ptOJduJZF6aHF01w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pDcn2/btrKHYXtYco/MaNe1ptOJduJZF6aHF01w1/img.png&quot; data-alt=&quot;[그림 1.8] 트랜잭션 처리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pDcn2/btrKHYXtYco/MaNe1ptOJduJZF6aHF01w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpDcn2%2FbtrKHYXtYco%2FMaNe1ptOJduJZF6aHF01w1%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;773&quot; height=&quot;434&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 1.8] 트랜잭션 처리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bc841643-f11e-456f-97c6-3ec6f0515b6e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f2966b31-89d8-498c-b4ae-dee9048aa486&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;입/출금에서 발생한 transaction은 transaction 처리를 검사하는 배치서버를 통해 검사합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-549ed0dc-c3cf-4509-ab0b-c714194ecc9c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8b58d2f5-b3e8-47dc-aeb4-1bd8f616b6f0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;자 여기서! 한가지 중요한점은 거래소 입/출금은 우리가 알고있는 입/출금의 개념이 아닙니다. 거래소 시스템에서 관리하는 지갑으로 돈이 들어온 경우 입금, 거래소 시스템에서 관리하고 있는 코인/토큰/원화가 빠져 나가는 것을 출금이라고 하며, 이 경우에만 트랜잭션을 발생합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8965317f-ee00-4124-8278-1d60c29f599e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;​&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-255c7486-63ba-49c5-9996-03ec30578276&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;즉, 거래소는 블록체인으로만 이루어진 시스템이 아닙니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-24b56c97-4d7f-440d-b536-34e8d2563e82&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-67d5e703-b06f-4e4a-99bf-400dfa97c7bd&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-1a665d45-f273-4bf1-89bf-3224336e609d&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;● &lt;b&gt;2. 지갑(wallet) &lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8e6bd4e4-aa05-49f4-a7f8-2d8a0f435598&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-94508eaf-c6d9-4fb3-89f6-37467f97306f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지갑은 거래소처럼 복잡한 시스템을 구축하지 않습니다. 지갑의 경우 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;비즈니스 모델이 약하기 때문에&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 심플한 형태로 구축합니다. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-76c2c4a7-6e8c-4fc8-902e-65e2e706fc30&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzLlJP/btrKK8SBZvT/YOzUBHHzOxP3KPKKIqDSJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzLlJP/btrKK8SBZvT/YOzUBHHzOxP3KPKKIqDSJK/img.png&quot; data-alt=&quot;[그림 2.1] 사용자 wallet, transaction 관리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzLlJP/btrKK8SBZvT/YOzUBHHzOxP3KPKKIqDSJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzLlJP%2FbtrKK8SBZvT%2FYOzUBHHzOxP3KPKKIqDSJK%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;480&quot; height=&quot;960&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 2.1] 사용자 wallet, transaction 관리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ec7a7a1c-7b29-4e7d-a90b-8025acc523f2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-19092da1-09b2-4ee6-afd9-adc652b75779&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;블록체인 자체에서 이력관리는 가능하나 사용자에게 띄워주기 위해 많은 리소스가 들어가므로 일부 데이터 시스템을 이용하여 사용자에게 편의성을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a83cc60e-ed7f-4eca-8d06-d769e8a9a79a&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baYZuF/btrKK8LPWyp/VxOfkbjeKtnkftIMKyRHek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baYZuF/btrKK8LPWyp/VxOfkbjeKtnkftIMKyRHek/img.png&quot; data-alt=&quot;[그림 2.2] 전송요청&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baYZuF/btrKK8LPWyp/VxOfkbjeKtnkftIMKyRHek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaYZuF%2FbtrKK8LPWyp%2FVxOfkbjeKtnkftIMKyRHek%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;480&quot; height=&quot;960&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 2.2] 전송요청&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d046f9cc-fa73-422b-a9be-85a6c5197351&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-29273a6a-1677-40a3-b0c0-4724b5212fa9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;지갑은 사용자 관리를 해야하기 때문에 회원가입을 하게되고 회원가입한 유저에 대해 지갑(주소)를 만들어 줍니다. 여기서는 출금(전송)을 하게되면, 즉시 transaction을 발생하고 사용자에게 응답합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2278f585-7d4f-462f-98cb-153312ff582d&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LZhT3/btrKHwUtAzK/5ezWILBzwVWMcK5OFuDFmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LZhT3/btrKHwUtAzK/5ezWILBzwVWMcK5OFuDFmk/img.png&quot; data-alt=&quot;[그림 2.3] 월랫 전송 프로세스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LZhT3/btrKHwUtAzK/5ezWILBzwVWMcK5OFuDFmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLZhT3%2FbtrKHwUtAzK%2F5ezWILBzwVWMcK5OFuDFmk%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;773&quot; height=&quot;428&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 2.3] 월랫 전송 프로세스&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div&gt;
&lt;p id=&quot;SE-7ffd1a43-77da-4fdb-af64-720ca9eae39b&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-edd0f952-f768-48aa-a33f-3d000f6b3bd5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-167f5473-4b0a-478f-9467-4282eef084ee&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;transaction이 블록에 포함되기 까지 기다리지 않고 만들어진 txHash를 즉시 응답하는 것이 포인트 입니다. 물론 기다려도 됩니다. 하지만 필자의 경우는 기다리지 않고 즉시 응답하여 사용자에게 대기중이라는 메시지를 띄워주는 형태로 시스템을 만들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f36851d5-e625-414b-ae1f-4fa7fcd0151e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5ab9339b-1f9b-4baa-85c5-4dd065f2ba8c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;월랫의 데이터 베이스는 사용자의 보유량을 따로 저장하지 않습니다. 잔액 조회시 디비가 아니라 블록체인 네트워크에 조회를 하여 보유량을 알려줍니다. 그렇기 때문에 어느 지갑에서나 사용가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-347f7af8-4810-413c-9ddb-d5d6d8ca1387&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-87f9f20b-efae-4f40-a694-f043835315bd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;※ 추가로. 지갑의 경우 데이터 베이스 없이 완전 P2P 형태로 개발 가능합니다. 이럴경우 해당 어플리케이션에서 관리하는 데이터 베이스(캐시, 로컬 데이터 베이스)를 지울경우 사용 내역을 볼 수 없고, 사용자 식별이 힘든 부분이 있어 일부 데이터 베이스 시스템에 의존합니다. 만약, 데이터 베이스 시스템 없이 구축하게 되면 블록체인 시스템에서 트랜잭션 처리 완료시 이벤트를 받아서 처리하면 됩니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c53dd128-3d20-4412-8e4a-f97269994047&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d00a6af3-7b9a-41fa-9a48-c82a9e494d60&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-8e447579-a818-47c2-b3a3-72973e081202&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;● &lt;b&gt;3. 암호화폐 결제(payment) &lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-86c45e7e-f5e6-4ffc-9063-c7425f930285&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e4f6d068-ef17-48ba-81f9-00b5dd8b3494&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;앞의 시스템을 응용하여 암호화폐 결제할 수 있습니다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-3324cfe6-3e29-4a4a-92d1-b2bc284ac7bd&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/niswI/btrKHdnmq1U/fCBBfMzF8ygr5sLugEsIQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/niswI/btrKHdnmq1U/fCBBfMzF8ygr5sLugEsIQ0/img.png&quot; data-alt=&quot;[그림 3.1] 암호화폐 기반 결제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/niswI/btrKHdnmq1U/fCBBfMzF8ygr5sLugEsIQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FniswI%2FbtrKHdnmq1U%2FfCBBfMzF8ygr5sLugEsIQ0%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;773&quot; height=&quot;549&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 3.1] 암호화폐 기반 결제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9c136dd7-2b2f-491e-bbeb-33e80a051b8a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0fd2a839-b400-4a36-bca1-606086ade8a2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[그림 3.1] 처럼 쇼핑몰에 암호화폐 결제방법을 사용하여 결제할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-c43846d3-8578-4614-ab2d-ae588bdbb9e1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9e576a1f-dc25-49de-8a55-afea197a063f&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;암호화폐 결제시 transaction을 처리방법은 앞에서 지갑(wallet)에서 트랜잭션을 기다리면 됩니다. 지갑(wallet) 시스템처럼 기다리지 않아도 되지만 기다리는 것이 구조상 훨씬 간단합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9a28afd3-cbf1-46dc-b9eb-4795f0fdf604&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nsyTO/btrKIr6bRz2/IkgPFzlfRAaNUfhinBlRnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nsyTO/btrKIr6bRz2/IkgPFzlfRAaNUfhinBlRnk/img.png&quot; data-alt=&quot;[그림 3.2] 결제 시스템 전송 프로세스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nsyTO/btrKIr6bRz2/IkgPFzlfRAaNUfhinBlRnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnsyTO%2FbtrKIr6bRz2%2FIkgPFzlfRAaNUfhinBlRnk%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;773&quot; height=&quot;314&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;[그림 3.2] 결제 시스템 전송 프로세스&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;div&gt;
&lt;p id=&quot;SE-7f151787-3f75-49d3-9c55-6ea7b8d1c33e&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결제 시스템의 경우 안정성이 중요하기 때문에 하나의 &lt;/span&gt;&lt;span style=&quot;color: #ff008c;&quot;&gt;트랜잭션(of DataBase)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 보장을 해줘야 합니다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;이렇게 되면 트랜잭션 처리 검사 배치서버를 두지 않아도 됩니다. 훨씬 더 심플해지는 대신 응답 시간이 다소 소요됩니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-efcdbd96-6f6a-44bd-8b5a-5fb84f636a3a&quot;&gt;
&lt;p id=&quot;SE-a93fc1ff-97ed-4d8d-a4d4-390575fab184&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7c07262a-c908-473e-a24f-405b7668a0b4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 결제 시스템의 경우 트랜잭션을 발생하고 해당 트랜잭션 처리를 기다려 줍니다. 트랜잭션 처리 응답을 받고 transactionComplete 테이블에 저장한후 사용자에게 결제가 완료됬다고 알려줍니다. 여기서 사용자는 일반 사용자일 수 있고 암호화폐 시스템을 연동한 다른 시스템일 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4a19c822-83bd-42b8-b295-4b59e6adaf9c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-28207054-0d58-4a5e-bdb6-0dd748f9f9be&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;물론 결제 시스템이기 때문에 사용자는 인증된 유저에 한해서만 결제를 진행하도록 해야합니다. 여기서 유저 인증은 API 키를 발급하는 형태로 진행할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-d522ff6c-bc2a-4e98-8243-2622498db928&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dcd3feb7-e1da-4f8d-9bbd-352178539e00&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이러한 부분을 SDK 형태로 만든다면 naver pay 처럼 사용 가능합니다. 현&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-eecbc898-ea21-4717-be8b-c2349568c13a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-e3ea5e99-24c2-480f-a268-dfe0979ea0bc&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-9bab7f48-bd88-4426-9f70-921e3efb16f2&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;● &lt;b&gt;4. 결합(combination)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-15ba4ddd-f37a-42f9-a488-c0c4284081e1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-b6319cb7-6c85-4671-8a74-bf099075e5bd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;앞에서 보여드린 3가지의 시스템은 독립적으로는 의미가 없습니다. 각각의 시스템은 하나의 시스템으로 만들어 졌을때 빛을 발합니다. 예를 들면 다음과 같이 시스템을 구축할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c7c46fe1-d13a-4092-9e7a-21c5a2f10e0c&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/04gEX/btrKHcPw9Fh/jYpBC89iKT0LaqPSDcD8KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/04gEX/btrKHcPw9Fh/jYpBC89iKT0LaqPSDcD8KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/04gEX/btrKHcPw9Fh/jYpBC89iKT0LaqPSDcD8KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F04gEX%2FbtrKHcPw9Fh%2FjYpBC89iKT0LaqPSDcD8KK%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;773&quot; height=&quot;557&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-abf4cf38-6bc0-4fe4-8969-e80521e53c7e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f93a90df-d535-4179-aa4b-58de9dbb2549&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저, wallet와 payment 시스템은 하나의 서버에서 /wallet, /payment로 라우트하여 처리합니다. /wallet의 경우 트랜잭션을 기다리지 않기 때문에 transaction 테이블을 사용하고, /payment는 transaction 처리를 기다리으모 transactionComplete 테이블을 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-50e9306a-9e49-45cf-ad2d-571db1aca3a4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-abc147e4-09eb-4b3d-b45f-68ef36fd8115&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;payment와 wallet은 동일한 계정을 사용하여 wallet에서 다른 사람으로부터 받은 암호화폐를 payment 시스템에서 사용가능 합니다. 여기서 거래소 시스템을 별도로 두는 이유는 거래소 시스템은 게더링 서버를 통해 유저 지갑에 보유중인 금액을 거래소 지갑으로 옮기기 때문에 결제시 해당 지갑주소에 보유금액이 없어 결제가 되지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dc156b56-ef38-4d70-a39d-f97ee0977dbe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7061b932-6fcb-4e95-8852-195d7dbfb650&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;/payment에서는 결제만 가능하고 다른 유저에게 코인 전송하는 기능은 없습니다. 다른 사람에게 암호화폐를 받기 위해서는 wallet을 통해 받거나 줄 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-50468738-1876-4322-b558-6aab070324b3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b3ad7829-b826-4b7b-944c-f0cadc9c0818&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-19a6e023-92dd-481e-bd2a-2aca04bcbbf1&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: GungSeo, serif;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;★ 정리&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8cba7398-7c37-4749-bd14-e5c4daee36f1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2e708a48-a828-4fb4-815f-e041da28ecd0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;먼저, 블록체인은 실시간 처리에서 사용하는 것 보다 데이터를 요청하고 즉시 응답을 받지 않아도 되는 시스템에서 사용하는 것이 좋습니다. 실생활에서도 요청과 즉시 바로 응답이 되는 시스템이 있지만 요청을 하더라도 며칠이 걸리는 작업이 있습니다. 블록체인은 이러한 곳에 활용한다면 좀 더 좋은 곳에 활용가능 하다고 생각합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f586cd86-aee2-4bb7-be1b-3e390f777841&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-744f4fdc-1f3c-4896-b6f7-82d26c242569&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 글에서 사용한 이미지 및 자료는 저와 저의 회사에서 실제 개발했던, 개발중인 시스템 구조도와 UI 입니다. 거래소는 현재 CBT 진행중인데 버그가 넘 많아서 골치 아프고 암호화폐 기반 결제 시스템은 프로젝트 기간이 워낙 짧아서 골치아퍼하는 멍개였습니다. 현재는 naverpay 처럼 시스템을 구축하기 위해 인증 부분과 SDK 설계 및 준비중입니다. SDk를 만들어서 배포하게 되면 다른 사람들도 같이 사용해야 하는 부분이라 문서화가 미흡한 부분 작업중입니다 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>exchange</category>
      <category>payment</category>
      <category>wallet</category>
      <category>거래소</category>
      <category>결제</category>
      <category>디앱</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <category>지갑</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/64</guid>
      <comments>https://meongae.tistory.com/64#entry64comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:40:34 +0900</pubDate>
    </item>
    <item>
      <title>[블록체인] 거래소는 시세를 어떻게 형성할까?</title>
      <link>https://meongae.tistory.com/63</link>
      <description>&lt;div id=&quot;SE-54be1432-d193-44c6-99ca-abc254948f9c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5df849b2-0a3b-4b87-a787-cbbfe26dc02a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;거래소의 호가창에 대해서 알아보겠습니다. 먼저 거래소의 기본적인 모습을 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-756f2a77-08b7-418d-bff0-0b31bfd6cb64&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6928c9b6-00f3-4761-9715-db3068d16205&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vFGKM/btrKGOOPXBe/8CLaPEW9myrcMHshtCqkpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vFGKM/btrKGOOPXBe/8CLaPEW9myrcMHshtCqkpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vFGKM/btrKGOOPXBe/8CLaPEW9myrcMHshtCqkpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvFGKM%2FbtrKGOOPXBe%2F8CLaPEW9myrcMHshtCqkpK%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;773&quot; height=&quot;483&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-02c24138-c83b-44d6-a225-0cea750b2dc6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e86e5869-1889-41db-abad-3da1906a5872&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;거래소마다 다르긴 하겠지만 일반적인 모습입니다. 여기서 호가창이란 등록된 매수(사기)/매도(팔기)를 띄어주는 부분입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a2a204bc-c466-4fc4-82b9-266c9fba3081&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 360px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;3&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;호가창&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;동현코인&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가격&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수량&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1008&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1007&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1006&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;600&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1005&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1004&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1003&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1002&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1001&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;999&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;998&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;997&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;996&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;995&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;600&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;994&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;993&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d6b197b8-e782-4962-982f-c82e76996826&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-2690d562-f899-423f-a6ee-c80c4f082444&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 테이블이 호가정보입니다. 해당 테이블이 어떤것을 의미 하는지 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8aee8c2b-b383-44a2-b8b7-b261673cadc5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dee154ad-1ddd-4206-ab7e-ab6478bafbe4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가장 좌측은 매수/매도를 구분짓는 부분입니다. 다음으로 가격과 수량입니다. 매도의 가장 아랫부분을 보면 다수의 사람들이 1001원에 100개의 코인을 팔겠다고 등록한 부분입니다. 한명이 1001원에 100개를 등록했을 수 있고 아닐 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-1a6f272a-034b-49b6-ab97-0c60b6cb660d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d9c2cd20-7997-4da9-86c9-1c2e4e089cb7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;6&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;호가창 구성 내용&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;3&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;3&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아아디&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가격&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수량&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아이디&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가격&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수량&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1001&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;50&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;14&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1001&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;50&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;15&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;999&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;50&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1002&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;120&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;16&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;998&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1002&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;80&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;17&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;997&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1003&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;18&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;996&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;6&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1004&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;19&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;995&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1005&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;150&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;20&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;994&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1006&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;21&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;993&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;9&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1007&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;22&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;999&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;150&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1008&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;23&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;998&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;11&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1008&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;24&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;997&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;12&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1006&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;25&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;996&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;13&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1005&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;350&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;26&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;995&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-efd521d8-0cfa-4c0f-84bc-96e060fb38f9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-cc23d698-c06a-4ead-86f8-0e7401c06128&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이러한 형태로 매수/매도가 등록되면 해당 데이터를 정렬하여 앞의 호가 테이블처럼 띄워주게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4379ec1e-ed25-4042-96be-c573fff5ed02&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7df8795f-597b-4051-9990-4887dc2353e0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;앞의 호가테이블처럼 시장가가 형성되면 이떄부터 거래가 이루어 지면서 시장가가 형성되는데 원리를 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3ec7de64-f91b-4970-a844-1a4e3096e4f5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-a1ee6b1b-f8d2-41ef-9ea1-488ce47398ba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;누군가가 1001원으로 50개를 매수하면 다음처럼 호가 테이블이 바뀝니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3e78f139-6f64-407c-9f89-a3d3af0b1a2d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-efd3fb21-7c6e-44fa-a543-72b43a08d18d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 360px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;3&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;호가창&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;멍개코인&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가격&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수량&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1008&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1007&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1006&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;600&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1005&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1004&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1003&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1002&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1001&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #e6000e;&quot;&gt;50&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;999&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;998&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;997&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;996&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;995&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;600&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;994&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;993&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1c629dbb-e93c-4e63-a4cd-8e81522e11a5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-39da40bb-00ad-4be8-a757-db2c8ae00d0a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1001원에 100개 있었지만 50개를 사갔기 때문에 50개를 매칭시켜줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-13d7ce2b-a40d-42c4-817c-8650d08dd470&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-574b858c-30f0-4c90-9e5e-802c940772ad&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 다시 1001원으로 40개 매수가 들어오면 다음과 같이 바뀝니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ca870cf0-0284-4327-b8f4-2054a291c725&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2541599e-215b-4cf8-94ac-625e3044b5b1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 360px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;3&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;호가창&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;멍개코인&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가격&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수량&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1008&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1007&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1006&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;600&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1005&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1004&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1003&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1002&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1001&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #e6000e;&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;999&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;998&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;997&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;996&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;995&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;600&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;994&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;993&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9f623833-d4b1-43ce-8c86-18050b5e9c21&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9f9e4079-01e6-42f3-af07-ebf749e61b72&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 가격에 등록된 매물이 있었기 때문에 바로 채결성공 합니다. 하지만 매수/매도 했을 때의 가격으로만 체결하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-6ff5e501-e29f-41cd-87eb-bc0df07c3663&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f5f08356-a1fa-4060-889d-2b293fe3265d&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 1002원으로 110개의 코인을 매수한다면 다음과 같이 바뀝니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ca7bb41d-ad75-46b2-aa1b-a599984742cd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-fddceb46-d30f-4e00-a997-01a10ef68c3f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan=&quot;3&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;호가창&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;멍개코인&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가격&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;수량&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1009&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1008&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1007&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1006&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;600&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1005&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1004&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1003&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;매도&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #e6000e;&quot;&gt;1002&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #e6000e;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;999&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;998&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;997&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;996&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;500&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;995&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;600&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;994&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;700&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;매수&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;993&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td colspan=&quot;1&quot; rowspan=&quot;1&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;800&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0f53e4b1-ec8f-4bd5-9b6c-3245337eabaa&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-f74fdd48-28d3-4949-9729-729a61ee9979&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1002원의 코인을 먼저사지 않고 1002원보다 싼 1001원을 먼저 구매한 후 남은량만큰 1002원에 등록된 코인을 구입합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-bfe789ab-46cd-4597-bb2f-f31b29a34915&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-77c64976-489e-4c17-9983-463f6f293bc6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;매수를 할 땐 매수할 때 등록한 금액보다 싼 금액을 우선적으로 채결합니다. 반대로 매도일 땐 비싼 금액을 우선적으로 채결합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-43783004-10fc-421c-a0ab-76acb056d9e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-5898f8e0-6612-48ea-b4ed-6d5300592174&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉, 다른사람들이 매수에 코인을 사겠다고 올렸고, A가 998원에 300개만큼 매도를 하면 998원에 등록된 300개가 아닌 1000원과 999원에 등록된 100, 200개를 판매하게 됩니다. 즉, 팔때는 비싼 가격에 팔 수 있도록 하고, 살땐 싼 가격에 살 수 있도록 매칭서버가 체결합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-4aade3ab-367a-405a-95ef-79179ae6bd47&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-f50128c9-5cef-4139-84c9-799161770310&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그렇기 때문에 매수/매도에서는 가장 비싼 금액과 가장 싼 금액을 우선적으로 체결합니다. 체결하는 서버를 매칭서버라고 하며, 간단하게 매칭 알고리즘이라고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-dfa427ba-1cf5-43af-a35e-d5e86e1955cd&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-0e29dd94-e3dc-433d-bf25-76200117811a&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이번글에서는 거래소에서 시세가 어떻게 형성하는지 간단히 알아보았습니다. 다음번에는 해당 내용을 코드적으로 접근해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/63</guid>
      <comments>https://meongae.tistory.com/63#entry63comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:34:57 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] transaction에 데이터를 포함하여 영원히 데이터 남기기</title>
      <link>https://meongae.tistory.com/62</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;transaction에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;input data&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 포함하여 전송하는 방법을 알아보겠습니다. input data가 머냐 하시는 분들이 있을텐데 다음 링크를 접속하면 다음과 같이 보실 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 예시&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://etherscan.io/tx/0xe4ee15d3f63db8464a649e3237ed83e930f9b3e40e842537a626745d1c96553c&quot;&gt;https://etherscan.io/tx/0xe4ee15d3f63db8464a649e3237ed83e930f9b3e40e842537a626745d1c96553c&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wdsP3/btrKF03gJQ9/KKkZk0Mk9SD0awFLaRvlu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wdsP3/btrKF03gJQ9/KKkZk0Mk9SD0awFLaRvlu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wdsP3/btrKF03gJQ9/KKkZk0Mk9SD0awFLaRvlu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwdsP3%2FbtrKF03gJQ9%2FKKkZk0Mk9SD0awFLaRvlu1%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 해당 이미지처럼 안 나오면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;view input As&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;버튼에서 UTF-8로 선택하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 계정 준비하기&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;1189&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkYDIh/btrKIziQIz9/e7R14QiTAyiL1G9ld4j1P0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkYDIh/btrKIziQIz9/e7R14QiTAyiL1G9ld4j1P0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkYDIh/btrKIziQIz9/e7R14QiTAyiL1G9ld4j1P0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkYDIh%2FbtrKIziQIz9%2Fe7R14QiTAyiL1G9ld4j1P0%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;788&quot; height=&quot;1212&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;1189&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트이기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ropsten 네트워크&lt;/b&gt;&lt;span&gt;에서 진행합니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;해당 계정의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;private key&lt;/b&gt;&lt;/span&gt;&lt;span&gt;를 이용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;myetherwallet&lt;/b&gt;&lt;/span&gt;&lt;span&gt;에서 정상적으로 읽어지는지 확인해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c43gHV/btrKHT2VGYT/j3b9YKP1DlU8aXWkjrt1R0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c43gHV/btrKHT2VGYT/j3b9YKP1DlU8aXWkjrt1R0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c43gHV/btrKHT2VGYT/j3b9YKP1DlU8aXWkjrt1R0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc43gHV%2FbtrKHT2VGYT%2Fj3b9YKP1DlU8aXWkjrt1R0%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;2560&quot; height=&quot;1600&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 읽어와집니다. 이제 여기서 input data를 포함하여 전송하는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. + 고급: 데이터 추가 버튼 누르기&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9Gs6k/btrKHaD65tu/P8cvGvlxl2Iw4ck4Tz35gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9Gs6k/btrKHaD65tu/P8cvGvlxl2Iw4ck4Tz35gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9Gs6k/btrKHaD65tu/P8cvGvlxl2Iw4ck4Tz35gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9Gs6k%2FbtrKHaD65tu%2FP8cvGvlxl2Iw4ck4Tz35gk%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;2560&quot; height=&quot;1600&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빨간색으로 표시해둔 부분을 눌러주면 다음과 같이 나타납니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHUCmj/btrKJ4plGZu/bPG3NXSzKRUaXH7xT9BMO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHUCmj/btrKJ4plGZu/bPG3NXSzKRUaXH7xT9BMO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHUCmj/btrKJ4plGZu/bPG3NXSzKRUaXH7xT9BMO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHUCmj%2FbtrKJ4plGZu%2FbPG3NXSzKRUaXH7xT9BMO0%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;2560&quot; height=&quot;1600&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터에 데이터를 넣으면 됩니다. 근데 그냥 키보드로 입력한 값을 넣으면 안됩니다. 인코딩된 데이터를 넣어야 정상적으로 transaction이 발생됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 데이터 인코딩&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.browserling.com/tools/url-encode&quot;&gt;https://www.browserling.com/tools/url-encode&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 사이트에 들어가면 데이터 인코딩을 할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Qglu/btrKGPUslt2/DGYxsozQGZThAZcgU3iVl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Qglu/btrKGPUslt2/DGYxsozQGZThAZcgU3iVl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Qglu/btrKGPUslt2/DGYxsozQGZThAZcgU3iVl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Qglu%2FbtrKGPUslt2%2FDGYxsozQGZThAZcgU3iVl1%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력란에 데이터를 입력한 후&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;URL Encode&lt;/b&gt;! 버튼을 눌러주면 인코딩된 결과를 볼 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DgGef/btrKJ5PnCGp/kKLjgwaXS0rbx3B09EPhTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DgGef/btrKJ5PnCGp/kKLjgwaXS0rbx3B09EPhTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DgGef/btrKJ5PnCGp/kKLjgwaXS0rbx3B09EPhTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDgGef%2FbtrKJ5PnCGp%2FkKLjgwaXS0rbx3B09EPhTK%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞의 결과는 '&lt;u&gt;안녕하세요&lt;/u&gt;'를 입력한 후 이코딩을 한 결과입니다. 여기서 %를 지웁니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; %지우기 전&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544406423861-1578949170_code_0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;EC&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;95&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;88&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;EB&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;85&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;95&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;ED&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;95&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;98&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;EC&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;84&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;B8&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;EC&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;9&lt;/span&gt;A&lt;span style=&quot;color: #a77f71;&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;94&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; % 지운 후&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544406423861-1578949170_code_1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;EC9588EB8595ED9598EC84B8EC9A94&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;%를 지운 결과를 복사한 후 앞의 고급: 데이터 추가를 눌었을 때 생긴 입력란에 넣어줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; transaction 발생&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqgwD1/btrKGQlBTeR/qV6K1vv0ldeXjexYskRGh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqgwD1/btrKGQlBTeR/qV6K1vv0ldeXjexYskRGh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqgwD1/btrKGQlBTeR/qV6K1vv0ldeXjexYskRGh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqgwD1%2FbtrKGQlBTeR%2FqV6K1vv0ldeXjexYskRGh0%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 넣어줄 땐&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;0x&lt;/b&gt;를 붙여서 넣어줍니다. 0x는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;16진수&lt;/b&gt;를 의미합니다. 받는 주소는 본인으로 한 후 0이더를 보내줍니다. 소량의 수수료만 지불하면 됩니다. 이제 트랜잭션을 생성해줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3fxDv/btrKHw1gBdX/dDeDnNg3SdujhJUvSz6MYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3fxDv/btrKHw1gBdX/dDeDnNg3SdujhJUvSz6MYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3fxDv/btrKHw1gBdX/dDeDnNg3SdujhJUvSz6MYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3fxDv%2FbtrKHw1gBdX%2FdDeDnNg3SdujhJUvSz6MYk%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 생성 버튼을 누르면 트랜잭션 전송하기 버튼이 나옵니다 여기서 트랜잭션 전송하기 버튼을 눌러줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWii49/btrKK9qqSR7/TMg69Nb8X2cFtH2YVRaxZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWii49/btrKK9qqSR7/TMg69Nb8X2cFtH2YVRaxZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWii49/btrKK9qqSR7/TMg69Nb8X2cFtH2YVRaxZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWii49%2FbtrKK9qqSR7%2FTMg69Nb8X2cFtH2YVRaxZ0%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 전송하기 버튼을 누르면 앞의 이미지처럼 모달창이 뜹니다. 여기서 네. 맞습니다! 전송합니다. 버튼을 눌러줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byWfei/btrKFSLeOYG/aQm44Eh2Gm9F9jHkg7Yn1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byWfei/btrKFSLeOYG/aQm44Eh2Gm9F9jHkg7Yn1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byWfei/btrKFSLeOYG/aQm44Eh2Gm9F9jHkg7Yn1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyWfei%2FbtrKFSLeOYG%2FaQm44Eh2Gm9F9jHkg7Yn1k%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하단에 transaction이 정상적으로 발생했다고 알림을 띄워줍니다. 여기서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;verify Transaction&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;버튼을 누르면 이더스캔에서 바로 확인가능 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3nGdL/btrKJ6AIfKc/VXoL4IUdwKgrLK8puqBEh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3nGdL/btrKJ6AIfKc/VXoL4IUdwKgrLK8puqBEh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3nGdL/btrKJ6AIfKc/VXoL4IUdwKgrLK8puqBEh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3nGdL%2FbtrKJ6AIfKc%2FVXoL4IUdwKgrLK8puqBEh0%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input data에 트랜잭션 발생시 포함한 데이터가 들어있습니다. View Input As 버튼을 눌러서 UTF-8을 눌러줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2quK8/btrKF7BoPbT/4vq8IxIhHYoTKqcnceFk90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2quK8/btrKF7BoPbT/4vq8IxIhHYoTKqcnceFk90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2quK8/btrKF7BoPbT/4vq8IxIhHYoTKqcnceFk90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2quK8%2FbtrKF7BoPbT%2F4vq8IxIhHYoTKqcnceFk90%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;디코딩 된 결과가 잘 표시됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 앞의 사이트에서 인코딩을 할 때 주의할 점은 한글이외의 영어, 숫자, 특수문자는 인코딩이 잘 되지 않습니다.&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 한글이외의 영문, 숫자, 특수문자 인코딩 방법&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한글 이외의 문자는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;아스키코드표&lt;/b&gt;를 참조하면 됩니다. 아스키코드표란 문자와 숫자를 1:1 매핑시킨 표입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL7Obf/btrKJ59ERjf/ye8qQgqb5pZbs9SNEkKINK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL7Obf/btrKJ59ERjf/ye8qQgqb5pZbs9SNEkKINK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL7Obf/btrKJ59ERjf/ye8qQgqb5pZbs9SNEkKINK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL7Obf%2FbtrKJ59ERjf%2Fye8qQgqb5pZbs9SNEkKINK%2Fimg.jpg&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;715&quot; height=&quot;396&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;396&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;397&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ejN21h/btrKGxs1Sjt/9s6eEKfEIk5MLkEKx9iRGK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ejN21h/btrKGxs1Sjt/9s6eEKfEIk5MLkEKx9iRGK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ejN21h/btrKGxs1Sjt/9s6eEKfEIk5MLkEKx9iRGK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FejN21h%2FbtrKGxs1Sjt%2F9s6eEKfEIk5MLkEKx9iRGK%2Fimg.jpg&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;715&quot; height=&quot;397&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;397&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 숫자 0을 입력하고 싶으면 16진수로 30이 됩니다. 10진수로 변환하면 48에 해당하는 숫자입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 '안녕하세요!'를 인코딩해보겠습니다. 먼저, '안녕하세요'는 앞의 인코딩 사이트를 가셔서 인코딩한 후 %를 모두 지워줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; '안녕하세요' 인코딩 결과&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544406423861-1578949170_code_2&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;EC9588EB8595ED9598EC84B8EC9A94&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 !가 0x21이기 때문에 인코딩 결과에 21을 붙이면 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; '안녕하세요!' 인코딩 결과&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544406423861-1578949170_code_3&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;EC9588EB8595ED9598EC84B8EC9A9421&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmsj4i/btrKHUgrVhA/Z624MbRmoAr7E7c2TyucS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmsj4i/btrKHUgrVhA/Z624MbRmoAr7E7c2TyucS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmsj4i/btrKHUgrVhA/Z624MbRmoAr7E7c2TyucS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdmsj4i%2FbtrKHUgrVhA%2FZ624MbRmoAr7E7c2TyucS0%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m7M41/btrKJ6OfOWJ/2cpPeK6xzvbaKxt2d0oRVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m7M41/btrKJ6OfOWJ/2cpPeK6xzvbaKxt2d0oRVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m7M41/btrKJ6OfOWJ/2cpPeK6xzvbaKxt2d0oRVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm7M41%2FbtrKJ6OfOWJ%2F2cpPeK6xzvbaKxt2d0oRVK%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'안녕하세요!'가 잘 출력됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 아스키코드 특수문자 알아보기&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스페이스: 0x20&lt;br /&gt;&lt;/span&gt;&lt;span&gt;엔터: 0x0A&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스페이스를 넣고싶을 땐 20, 엔터를 넣고 싶을 땐 0A를 넣으면 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>ASCII</category>
      <category>input data</category>
      <category>아스키 코드</category>
      <category>이더리움</category>
      <category>트랜잭션</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/62</guid>
      <comments>https://meongae.tistory.com/62#entry62comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:31:03 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] abi-decoder를 이용하여 inputData 해독하기</title>
      <link>https://meongae.tistory.com/61</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;안녕하세요. 멍개입니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;b&gt;abi-decoder&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라이브러리를 이용하여 transaction에 포함된 inputData를 해석하는 방법을 다뤄보도록 하겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; abi-decoder 모듈설치&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544320276872-1730167810_code_0&quot;&gt;
&lt;pre id=&quot;code_1661585256162&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm install --save abi-decoder&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm을 이용하면 간단하게 설치할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; abi 추출하기&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;transaction&lt;/b&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;inputData&lt;/b&gt;를 디코딩하기 위해서는 해당 컨트랙트의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ABI&lt;/b&gt;가 필요합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544320276872-1730167810_code_1&quot;&gt;
&lt;pre id=&quot;code_1661585270793&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity 0.5;

contract test {
    uint var1 = 10;
    string var2 = &quot;hello world&quot;;
    
    function setData(uint a, uint b, string memory c) public {
        var1 = a + b;
        var2 = c;
    }
    
    function getData() public view returns(uint) {
        return var1 + 10;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz7arU/btrKGxNnFmj/VCChYeB1vaMxZ6PKEZg6P0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz7arU/btrKGxNnFmj/VCChYeB1vaMxZ6PKEZg6P0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz7arU/btrKGxNnFmj/VCChYeB1vaMxZ6PKEZg6P0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz7arU%2FbtrKGxNnFmj%2FVCChYeB1vaMxZ6PKEZg6P0%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ABI 복사 버튼을 눌러줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544320276872-1730167810_code_2&quot;&gt;
&lt;pre id=&quot;code_1661585278441&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[
	{
		&quot;constant&quot;: true,
		&quot;inputs&quot;: [],
		&quot;name&quot;: &quot;getData&quot;,
		&quot;outputs&quot;: [
			{
				&quot;name&quot;: &quot;&quot;,
				&quot;type&quot;: &quot;uint256&quot;
			}
		],
		&quot;payable&quot;: false,
		&quot;stateMutability&quot;: &quot;view&quot;,
		&quot;type&quot;: &quot;function&quot;
	},
	{
		&quot;constant&quot;: false,
		&quot;inputs&quot;: [
			{
				&quot;name&quot;: &quot;a&quot;,
				&quot;type&quot;: &quot;uint256&quot;
			},
			{
				&quot;name&quot;: &quot;b&quot;,
				&quot;type&quot;: &quot;uint256&quot;
			},
			{
				&quot;name&quot;: &quot;c&quot;,
				&quot;type&quot;: &quot;string&quot;
			}
		],
		&quot;name&quot;: &quot;setData&quot;,
		&quot;outputs&quot;: [],
		&quot;payable&quot;: false,
		&quot;stateMutability&quot;: &quot;nonpayable&quot;,
		&quot;type&quot;: &quot;function&quot;
	}
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; transaction 발생하여 inputdata 얻기&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kRn0n/btrKLhorwrL/ZiMRf08cLbbBWkQM4Fo7Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kRn0n/btrKLhorwrL/ZiMRf08cLbbBWkQM4Fo7Jk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kRn0n/btrKLhorwrL/ZiMRf08cLbbBWkQM4Fo7Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkRn0n%2FbtrKLhorwrL%2FZiMRf08cLbbBWkQM4Fo7Jk%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setData 함수를 호출하여 transaction을 발생합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/61NQk/btrKIy5jS26/AJ5kH8EMMSKSmZ9cDgyqgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/61NQk/btrKIy5jS26/AJ5kH8EMMSKSmZ9cDgyqgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/61NQk/btrKIy5jS26/AJ5kH8EMMSKSmZ9cDgyqgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F61NQk%2FbtrKIy5jS26%2FAJ5kH8EMMSKSmZ9cDgyqgk%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544320276872-1730167810_code_3&quot;&gt;
&lt;pre id=&quot;code_1661585292824&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;0xf8075633000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000a68656c6c20776f726c6400000000000000000000000000000000000000000000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;inputData&lt;/b&gt;는 to가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CA&lt;/b&gt;(contract address)라면 블록체인 네트워크에서 노드가 읽어서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;EVM&lt;/b&gt;에서 실행하게 됩니다. 이제 inputData를 해독해보겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; inputData 해독&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 ABI와 transaction에 포함된 InputData를 복사합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544320276872-1730167810_code_4&quot;&gt;
&lt;pre id=&quot;code_1661585305208&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const abiDecoder = require('abi-decoder');

const testABI = [
	{
		&quot;constant&quot;: true,
		&quot;inputs&quot;: [],
		&quot;name&quot;: &quot;getData&quot;,
		&quot;outputs&quot;: [
			{
				&quot;name&quot;: &quot;&quot;,
				&quot;type&quot;: &quot;uint256&quot;
			}
		],
		&quot;payable&quot;: false,
		&quot;stateMutability&quot;: &quot;view&quot;,
		&quot;type&quot;: &quot;function&quot;
	},
	{
		&quot;constant&quot;: false,
		&quot;inputs&quot;: [
			{
				&quot;name&quot;: &quot;a&quot;,
				&quot;type&quot;: &quot;uint256&quot;
			},
			{
				&quot;name&quot;: &quot;b&quot;,
				&quot;type&quot;: &quot;uint256&quot;
			},
			{
				&quot;name&quot;: &quot;c&quot;,
				&quot;type&quot;: &quot;string&quot;
			}
		],
		&quot;name&quot;: &quot;setData&quot;,
		&quot;outputs&quot;: [],
		&quot;payable&quot;: false,
		&quot;stateMutability&quot;: &quot;nonpayable&quot;,
		&quot;type&quot;: &quot;function&quot;
	}
]
abiDecoder.addABI(testABI);

// testData엔 transaction의 inputData를 넣어줍니다.
const  testData  =  &quot;0xf80756330000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000006ed97aceba19c0000000000000000000000000000000000000000000000000000&quot;;
const decodedData = abiDecoder.decodeMethod(testData);

console.log(decodedData)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1544320276872-1730167810_code_5&quot;&gt;
&lt;pre id=&quot;code_1661585310820&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{ name: 'setData',
  params:
   [ { name: 'a', value: '1', type: 'uint256' },
     { name: 'b', value: '2', type: 'uint256' },
     { name: 'c', value: 'hell world', type: 'string' } ] }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행결과를 보면 name엔 호출함수와 params엔 전달된 인자 정보를 볼 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>ABI</category>
      <category>evm</category>
      <category>디코드</category>
      <category>솔리디티</category>
      <category>이더리움</category>
      <category>트랜잭션</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/61</guid>
      <comments>https://meongae.tistory.com/61#entry61comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:28:44 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] transaction을 보고 contract 생성을어떻게 할까</title>
      <link>https://meongae.tistory.com/60</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;smart contract에 대해서 알아보도록 하겠습니다. &lt;/span&gt;&lt;/p&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;span&gt;간단하게 smart contract의 생성원리를 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 컨트랙트 배포 후 확인&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/smLzD/btrKGOOPIbz/6Rxf6vdpiT2wFrtN33CJUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/smLzD/btrKGOOPIbz/6Rxf6vdpiT2wFrtN33CJUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/smLzD/btrKGOOPIbz/6Rxf6vdpiT2wFrtN33CJUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsmLzD%2FbtrKGOOPIbz%2F6Rxf6vdpiT2wFrtN33CJUK%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;1681&quot; height=&quot;1051&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnKX6f/btrKLg389u1/CJMXSKN0kEOkVI6CnAgvFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnKX6f/btrKLg389u1/CJMXSKN0kEOkVI6CnAgvFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnKX6f/btrKLg389u1/CJMXSKN0kEOkVI6CnAgvFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnKX6f%2FbtrKLg389u1%2FCJMXSKN0kEOkVI6CnAgvFk%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;1681&quot; height=&quot;1051&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTyDYI/btrKLhaUg38/6VLI2nJkbYv28qRUQXDa5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTyDYI/btrKLhaUg38/6VLI2nJkbYv28qRUQXDa5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTyDYI/btrKLhaUg38/6VLI2nJkbYv28qRUQXDa5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTyDYI%2FbtrKLhaUg38%2F6VLI2nJkbYv28qRUQXDa5k%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;1681&quot; height=&quot;1051&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;transaction 정보를 보면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;contract create&lt;/b&gt;&lt;span&gt;라고 표시됩니다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움은 어떻게 contract 생성을 알고 contract create라고 표시하는지 알아보겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; contract 배포직후 transaction 확인&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tI5se/btrKGo3VIOl/PumCQNOMuifwiXMli7FyCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tI5se/btrKGo3VIOl/PumCQNOMuifwiXMli7FyCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tI5se/btrKGo3VIOl/PumCQNOMuifwiXMli7FyCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtI5se%2FbtrKGo3VIOl%2FPumCQNOMuifwiXMli7FyCK%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;1681&quot; height=&quot;1051&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움에서 컨트랙트가 배포할 때 일반적인 transaction과 다르게 to를 비워서 보냅니다. 또한, Input Data를 컨트랙트를 작성한 코드를 컴파일한 결과를 포함하여 보냅니다.&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 트랜잭션을 처리하는 노드는 to가 비어있고 Input Data가 있으면, contract 생성을 하게됩니다. 이때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Contract Address(CA)&lt;/b&gt;를 생성합니다. 이때 Input Data를 해당 컨트랙트에 저장을 합니다. 이렇게 생성된 계정을 To에 집어넣어 Transaction을 완성하게 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>블록체인</category>
      <category>스마트 컨트랙트</category>
      <category>스마트 콘트랙트</category>
      <category>이더리움</category>
      <category>트랜잭션</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/60</guid>
      <comments>https://meongae.tistory.com/60#entry60comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:26:35 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] transaction 발생 시 - Warning! Error encountered during contract execution [Out of gas] 에러</title>
      <link>https://meongae.tistory.com/59</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더리움에서 스마트 컨트랙트를 개발하다보면 상당히 다양한 에러를 접할 수 있습니다. 그중에 하나가 gas와 관련된 에러입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 정상 Transaction VS 비정상 Transaction&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 정상적인 transaction과 비정상적으로 처리된 transaction을 비교해보겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 정상 Transaction&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfjL0T/btrKHYwrdPw/6QYSNIg2wBdceMpBB3tgt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfjL0T/btrKHYwrdPw/6QYSNIg2wBdceMpBB3tgt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfjL0T/btrKHYwrdPw/6QYSNIg2wBdceMpBB3tgt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfjL0T%2FbtrKHYwrdPw%2F6QYSNIg2wBdceMpBB3tgt1%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;2310&quot; height=&quot;1714&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적인 transaction은 Success 상태가 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 비정상 Transaction&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y0um9/btrKF0hVz29/gjE3LofCzSUleEkWogMkk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y0um9/btrKF0hVz29/gjE3LofCzSUleEkWogMkk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y0um9/btrKF0hVz29/gjE3LofCzSUleEkWogMkk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy0um9%2FbtrKF0hVz29%2FgjE3LofCzSUleEkWogMkk1%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;2306&quot; height=&quot;1708&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gas 문제로 발생된 트랜잭션 실패는 Out of gas라고 표기됩니다. 과연 이 문제가 왜 발생할까요??&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;573&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbAjcw/btrKHvgTwOg/KSWyZKGajvo3SkIEmPqxqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbAjcw/btrKHvgTwOg/KSWyZKGajvo3SkIEmPqxqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbAjcw/btrKHvgTwOg/KSWyZKGajvo3SkIEmPqxqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbAjcw%2FbtrKHvgTwOg%2FKSWyZKGajvo3SkIEmPqxqK%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;2306&quot; height=&quot;1708&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;573&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적색으로 박스친 부분을 명심해야 합니다. Gas Used By Transaction(해당 트랜잭션을 실행하면서 소모한 가스)가 Gas Limit을 넘치면 앞의 에러처럼 발생합니다. 이때는 해결법이 매우매우 간단합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 해결방법&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;1198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSWE7D/btrKHefujrn/n6RwA6rxtDGjr6Y5gHSk9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSWE7D/btrKHefujrn/n6RwA6rxtDGjr6Y5gHSk9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSWE7D/btrKHefujrn/n6RwA6rxtDGjr6Y5gHSk9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSWE7D%2FbtrKHefujrn%2Fn6RwA6rxtDGjr6Y5gHSk9K%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;714&quot; height=&quot;1198&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;1198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결 방법은 gas limit(가스한도)를 올려서 트랜잭션을 발생하면 됩니다. 앞의 이미지는 metamask 기준이고 사용하는 지갑에서 gas limit(가스한도)를 더 높여주고 실행하면 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 gas limit이 21000은 이더전송을 의미합니다. 또한, gas는 ethereum에서 수수료를 지불하는 수단입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/59</guid>
      <comments>https://meongae.tistory.com/59#entry59comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:25:05 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] solidity - address 관리방법(address, address payabl 타입)</title>
      <link>https://meongae.tistory.com/58</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번글에서는 solidity로 개발한 스마트 컨트랙트에서 다른 계정으로 이더를 전송하는 방법에 대해서 알아보겠습니다. 이번글도 0.5 버전을 기준으로 작성됩니다. 물론 이전 버전과 어떤 차이가 있는지도 함께 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 컨트랙트에서 다른 계정으로 이더를 전송하기 위해서는 컨트랙트에서 이더를 보유하고 있어야 합니다. 즉, 다른 계정으로부터 이더를 전송받아야 하는데 전송 받는방법 부터 알아보겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 이더 전송받는 방법&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1543191564769--209869357_code_0&quot;&gt;
&lt;pre id=&quot;code_1661584848605&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.5;

contract address05 {
    function () external payable{
        
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;solidity에서는 이름이 없는 함수를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;fallback&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수라고 하는데 fallback 함수에 external과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;payable&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;옵션을 붙여주어 해당 컨트랙트가 외부 계정으로부터 돈을 입금받을 수 있도록 합니다. payable은 외부 계정으로부터 이더를 받으면 호출되는 함수입니다. 만약&amp;nbsp; payable 키워드가 존재하지 않는다면 해당 컨트랙트는 외부 계정으로부터 이더를 전송받지 못하게 됩니다.&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;추가적으로 external은 외부에서만 호출할 수 있는 함수를 의미합니다. 즉 해당 컨트랙트 내부에서는 해당 함수를 호출할 수 없음을 의미하고 있고 0.5 버전부터는 fallback 함수는 external을 강제하고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 0.5에서 이더 전송방법&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0.5부터는 이더를 전송하기 위해서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;address payable&lt;/b&gt;을 이용해야 합니다. 이전 버전에서는 address 타입에서 send와 transfer를 제공하여 바로 사용할 수 있었지만 0.5 버전부터는 address 타입도 address payable 타입으로 변환을 해야 정상적으로 전송이 가능해집니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1543191564769--209869357_code_1&quot;&gt;
&lt;pre id=&quot;code_1661584950443&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// address payable to == address(uint160(to))

pragma solidity ^0.5;

contract address05 {
    function () external payable{
        
    }
    
    function oldSend(address to, uint value) public {
        to.send(value * (10 ** 18));
    }
    
    function newSend(address payable to, uint value) public {
        to.transfer(value * (10 ** 18));
    }
    
    function newSendTypeConvert1(address to, uint value) public {
        address payable convertedTo= address(uint160(to));
        convertedTo.send(value * (10 ** 18));
    }
    
    function newSendTypeConvert3(address to, uint value) public {
        address(uint160(to)).send(value * (10 ** 18));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nX8pr/btrKGO2m9N4/f58Tvyuj7S3PScmpFPd0b0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nX8pr/btrKGO2m9N4/f58Tvyuj7S3PScmpFPd0b0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nX8pr/btrKGO2m9N4/f58Tvyuj7S3PScmpFPd0b0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnX8pr%2FbtrKGO2m9N4%2Ff58Tvyuj7S3PScmpFPd0b0%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이전 버전처럼 사용하면 앞의 이미지처럼 에러가 발생하게 됩니다. address payable로 변환을 해야 정상적으로 컴파일이 됩니다.&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;address payable은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;address(uint160())&lt;/b&gt;&lt;/span&gt;&lt;span&gt;으로 변환해주면 됩니다. 또한 msg.sender로 가져오는 address도 address payable 타입입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1543191564769--209869357_code_2&quot;&gt;
&lt;pre id=&quot;code_1661584957226&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function giveBack() internal {
    msg.sender.transfer(msg.value);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;msg.sender로 가져온 address는 address payable 타입이기 때문에 변환없이 transfer를 사용할 수 있습니다. 또한 msg.sender로 transfer 하기 위해서는 internal 형태의 함수이거나 payable 타입의 함수여야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 0.5 부터는 send가 아닌 transfer 사용을 권장하고 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;● 이더전송 테스트 해보기&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1543191564769--209869357_code_3&quot;&gt;
&lt;pre id=&quot;code_1661584971585&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// address payable to == address(uint160(to))

pragma solidity ^0.5;

contract address05 {
    function () external payable{}
    
    function newSend(address payable to, uint value) public {
        to.transfer(value * (10 ** 18));
    }
    
    function newSendTypeConvert1(address to, uint value) public {
        address payable convertedTo= address(uint160(to));
        convertedTo.send(value * (10 ** 18));
    }
    
    function newSendTypeConvert3(address to, uint value) public {
        address(uint160(to)).send(value * (10 ** 18));
    }
    
    function getBalance(address to) view public returns(uint) {
        return address(to).balance;
    }
    
    function giveBack() internal {
        msg.sender.transfer(msg.value);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞의 코드로 배포를 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;※ 배포정보&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bq9qx9/btrKGQy9Qsn/FYQlX7wfIVsOPdpwd9uxt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bq9qx9/btrKGQy9Qsn/FYQlX7wfIVsOPdpwd9uxt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bq9qx9/btrKGQy9Qsn/FYQlX7wfIVsOPdpwd9uxt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbq9qx9%2FbtrKGQy9Qsn%2FFYQlX7wfIVsOPdpwd9uxt1%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QEusg/btrKJ6tXc0a/wVkiUO3tOUUyAhhkMFwha1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QEusg/btrKJ6tXc0a/wVkiUO3tOUUyAhhkMFwha1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QEusg/btrKJ6tXc0a/wVkiUO3tOUUyAhhkMFwha1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQEusg%2FbtrKJ6tXc0a%2FwVkiUO3tOUUyAhhkMFwha1%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1543191564769--209869357_code_4&quot;&gt;
&lt;pre id=&quot;code_1661584986674&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;배포 네트워크 : ropsten network
컨트랙트 배포 address(EOA) : 0x98e748f1d7b17e9f99210044a609cfbfe7604f0d
배포된 컨트랙트 address(CA): 0xbe649afefd32c806a4668d3fc0800d929a400f63&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더스캔을 통해서도 배포된 컨트랙트의 자세한 정보를 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 배포된 컨트랙트로 이더전송&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UBZ2x/btrKGOnLzQ0/CHwSfN1BnZg84c0ck36Js1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UBZ2x/btrKGOnLzQ0/CHwSfN1BnZg84c0ck36Js1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UBZ2x/btrKGOnLzQ0/CHwSfN1BnZg84c0ck36Js1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUBZ2x%2FbtrKGOnLzQ0%2FCHwSfN1BnZg84c0ck36Js1%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5이더를 배포된 컨트랙트에 전송해줍니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnsaWe/btrKFQzRyvO/hEKREkhk0KXUEzu4BILVV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnsaWe/btrKFQzRyvO/hEKREkhk0KXUEzu4BILVV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnsaWe/btrKFQzRyvO/hEKREkhk0KXUEzu4BILVV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnsaWe%2FbtrKFQzRyvO%2FhEKREkhk0KXUEzu4BILVV0%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yvsiV/btrKFPAYFij/mpZKIa81Nix0tcI8gtcfU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yvsiV/btrKFPAYFij/mpZKIa81Nix0tcI8gtcfU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yvsiV/btrKFPAYFij/mpZKIa81Nix0tcI8gtcfU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyvsiV%2FbtrKFPAYFij%2FmpZKIa81Nix0tcI8gtcfU1%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배포한 컨트랙트에서 getBalance() 함수에 이더 보유를 확인할 컨트랙트 주소를 인자로 전달하여 호출하거나 이더스캔에서 확인을 할 수 있습니다. 참고로 이더리움은 decimals이 18이기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;1000000000000000000 wei가 1ether&lt;/b&gt;가 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 컨트랙트에 있는 이더 외부계정에 전송&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1543191564769--209869357_code_5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;전송받을 계정 &lt;span style=&quot;color: #a77f71;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #e57523;&quot;&gt;0x74537181C008e71BB3Fb6E4F4780f04A3470f551&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIu3E1/btrKHcPwncj/xr66yqkdcPuCIlmJYCbqi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIu3E1/btrKHcPwncj/xr66yqkdcPuCIlmJYCbqi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIu3E1/btrKHcPwncj/xr66yqkdcPuCIlmJYCbqi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIu3E1%2FbtrKHcPwncj%2Fxr66yqkdcPuCIlmJYCbqi1%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 컨트랙트에 존재하는 이더리움중 일부를 해당 계정으로 전송해보겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wcggR/btrKGyS4jgX/QHHJhgqCfl5DLGT4msWM00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wcggR/btrKGyS4jgX/QHHJhgqCfl5DLGT4msWM00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wcggR/btrKGyS4jgX/QHHJhgqCfl5DLGT4msWM00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwcggR%2FbtrKGyS4jgX%2FQHHJhgqCfl5DLGT4msWM00%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션을 발생 시키고 해단 트랜잭션이 block에 포함될 때까지 기다린 후&amp;nbsp;이더스캔을 접속하여 확인하면 이더 전송이 된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chJjlL/btrKHVzGmxD/pEWBhfxcFXkiNYA1T3pt4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chJjlL/btrKHVzGmxD/pEWBhfxcFXkiNYA1T3pt4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chJjlL/btrKHVzGmxD/pEWBhfxcFXkiNYA1T3pt4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchJjlL%2FbtrKHVzGmxD%2FpEWBhfxcFXkiNYA1T3pt4k%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW6XzF/btrKGpocNhN/MjfM2HOzeBFxy0moy2sre1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW6XzF/btrKGpocNhN/MjfM2HOzeBFxy0moy2sre1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW6XzF/btrKGpocNhN/MjfM2HOzeBFxy0moy2sre1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW6XzF%2FbtrKGpocNhN%2FMjfM2HOzeBFxy0moy2sre1%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;transaction의 경우는 지갑을 통해서 주고 받은 이더가 표시되고 컨트랙트 내부에서 전송이 발생된 경우는 internal Txns에서 몇 이더를 전송했는지 확인 가능합니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TJWmf/btrKF03gqOX/XQxsh8D2n2kUkBzn1lBqP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TJWmf/btrKF03gqOX/XQxsh8D2n2kUkBzn1lBqP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TJWmf/btrKF03gqOX/XQxsh8D2n2kUkBzn1lBqP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTJWmf%2FbtrKF03gqOX%2FXQxsh8D2n2kUkBzn1lBqP0%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;2562&quot; height=&quot;1602&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이더를 전송받은 계정또한 이더스캔에서 확인 가능합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;1177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cL9F5k/btrKK9qqAga/XkEPEFtkoiDCToF7RDYFzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cL9F5k/btrKK9qqAga/XkEPEFtkoiDCToF7RDYFzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cL9F5k/btrKK9qqAga/XkEPEFtkoiDCToF7RDYFzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcL9F5k%2FbtrKK9qqAga%2FXkEPEFtkoiDCToF7RDYFzK%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;792&quot; height=&quot;1206&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;1177&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;metamask 지갑에서도 확인 가능합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;0.5 버전에서는 이더를 전송하기 위해서는 address payable을 사용하여 전송하게 되는데 좀 더 신경써서 전송하라는 의미인 것 같습니다.&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>address</category>
      <category>INTERNAL</category>
      <category>payable</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/58</guid>
      <comments>https://meongae.tistory.com/58#entry58comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:23:52 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] solidity - call, delegatecall</title>
      <link>https://meongae.tistory.com/57</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; solidity에서 call과 delegatecall에 대해서 다뤄보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-33daf006-0063-4bef-9b7e-9465b12568c2&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-451ed33d-ed75-48b9-96fc-c38e9c4eb753&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우선 이번글은 solidity 0.5 버전 기준으로 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-7b99c0d4-7d5a-41ab-bf11-485488466dd4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;call과 delegatecall은 0.5 버전 전, 후로 사용법이 바뀌었습니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div id=&quot;SE-9f26b28e-059a-4fdf-be57-2a555d1f86fb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-caf8dde1-e9bf-4dee-9d4d-d00d01d3015c&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● 샘플코드&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bc5f2831-e49e-4bab-9a4a-65ad60ff0fe9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0747f450-63ac-44e8-8cae-cdbbd1459770&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저, call과 delegatecall을 사용한 sample 코드부터 확인하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661584560597&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pragma solidity ^0.5;

contract Sample1 {

    uint public t ;

    constructor() public {
        
    }
    event L(uint a, uint b, address c);
    
    function test(uint a, uint b) public returns(uint){
        t = a + b;
        emit L(a, b, msg.sender);
        return a + b;
    }
}

contract Sample2 {
    uint public t;
    
    constructor() public {
        
    }
    
    function callTest(address contractAddr, uint to, uint value) public returns (bool, bytes memory, address) {
        (bool success, bytes memory data) = address(contractAddr).call(abi.encodeWithSignature(&quot;test(uint256,uint256)&quot;, to, value));
        
        if(!success) {
            revert();
        }
        
        //(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes));

        return (success, data, contractAddr);
    }
    
    function delegatecallTest(address contractAddr, uint to, uint value) public returns (bool, bytes memory, address) {
        (bool success, bytes memory data) = address(contractAddr).delegatecall(abi.encodeWithSignature(&quot;test(uint256,uint256)&quot;, to, value));
        
        if(!success) {
            revert();
        }
        
        //(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes));

        return (success, data, contractAddr);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c8bf488c-3ec2-4d3d-b9b1-4fac29043aa6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-288fcc65-e2a1-4f05-8948-7693b0511a60&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 샘플코드 배포&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f08243f7-3e49-4437-a23f-f4fea1ec304a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-126888f1-79da-454b-8828-6bc6af3d0648&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;샘플 코드를 보면 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Sample1&lt;/b&gt;&lt;/span&gt;&lt;span&gt;과 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Sample2&lt;/b&gt;&lt;/span&gt;&lt;span&gt;가 존재합니다. 각각 배포를 해줍니다. 순서는 상관없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b854dcc1-5842-4130-a834-1a52c197fa1b&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW0EYN/btrKLabNUzR/7bBXWNDpmxr4ekK92Rk3E0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW0EYN/btrKLabNUzR/7bBXWNDpmxr4ekK92Rk3E0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW0EYN/btrKLabNUzR/7bBXWNDpmxr4ekK92Rk3E0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW0EYN%2FbtrKLabNUzR%2F7bBXWNDpmxr4ekK92Rk3E0%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;773&quot; height=&quot;435&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-604eac0a-9e4f-4ad9-93eb-efc0a6ca6cbb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-c7981bdc-8780-4151-ac8a-eb8749683ddc&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;remix를 이용하면 매우 편하게 배포가 가능합니다. 빠른 테스트를 위해 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Javascript VM&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;을 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-2d06fac6-edfd-40c2-b82f-1eb107af3e80&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우측 하단에서 배포된 컨트랙트를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7dec8ef8-4ccd-403f-845a-c045627adae4&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-947efc0f-8c60-446d-9603-0c33833a91d1&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 배포정보 확인하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-740e2061-fabe-4e50-a23b-a030fcabb449&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-04a0da25-d741-4bc7-99b2-c08ffb2647be&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 사진에서 &lt;/span&gt;&lt;span&gt;&lt;b&gt;검정&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #0076c8;&quot;&gt;&lt;b&gt;파랑&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #f12f22;&quot;&gt;&lt;b&gt;빨강&lt;/b&gt;&lt;/span&gt;&lt;span&gt;박스 순으로 &lt;/span&gt;&lt;span&gt;&lt;b&gt;트랜잭션 호출자&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #0076c8;&quot;&gt;&lt;b&gt;sample1 컨트랙트&lt;/b&gt;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #f12f22;&quot;&gt;&lt;b&gt;sample2 컨트랙트&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-1bed4b80-2db6-45e4-9a77-69516dddd91b&quot;&gt;
&lt;pre id=&quot;code_1661584625931&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;트랜잭션 발생자(EOA): 0xca35b7d915458ef540ade6068dfe2f44e8fa733c
sample1 contract address(ca): 0x692a70d2e424a56d2c6c27aa97d1a86395877b3a
sample2 contract address(ca): 0xbbf289d846208c16edc8474705c748aff07732db&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-580a68b6-1c34-45ff-9ede-630c9a022435&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-9fa6a8eb-ff44-462e-96b4-939d8b8f2001&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 정보는 테스트 할 때마다 다르게 배포됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-043f7254-429f-4cc2-9309-6a4c32835028&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-8a75966f-e9b5-4020-ac3a-f1c10f1c5dd4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; Sample1 컨트랙트 직접 호출&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-23578865-fd73-4461-9d60-17f943dba6f7&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lfmr7/btrKGR5Rdul/9CbKLXmHHJTDwv8wkm7sh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lfmr7/btrKGR5Rdul/9CbKLXmHHJTDwv8wkm7sh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lfmr7/btrKGR5Rdul/9CbKLXmHHJTDwv8wkm7sh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flfmr7%2FbtrKGR5Rdul%2F9CbKLXmHHJTDwv8wkm7sh1%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;528&quot; height=&quot;282&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9f1aa546-4767-44a1-9d6b-f48f91095164&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-88fc9abd-6a13-4156-9d13-c0c8c6748225&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;test 함수를 호출할 때 1과 2를 전달합니다. Sample1의 test()는 2개의 인자를 받아서 합하여 t에 저장합니다. 그리고 event를 호출하여 전달받은 2개의 인자와 해당 함수를 호출한 address를 인자로 전달합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-df6252a9-563b-4b59-ad47-af56163d6bd3&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DFyLI/btrKGR5Rdtc/2b601LawasM1PfGAJNoihk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DFyLI/btrKGR5Rdtc/2b601LawasM1PfGAJNoihk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DFyLI/btrKGR5Rdtc/2b601LawasM1PfGAJNoihk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDFyLI%2FbtrKGR5Rdtc%2F2b601LawasM1PfGAJNoihk%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;773&quot; height=&quot;202&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-29d48298-a328-43b4-9929-6b7d03d445a7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-3f84ae22-60d5-4225-824b-27c1b91453e9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;test() 호출 후 logs를 확인해보면 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-bc9aff0b-99a0-4711-8172-7f4029ca6267&quot;&gt;
&lt;pre id=&quot;code_1661584643722&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;args&quot;: {
    &quot;a&quot;: &quot;1&quot;,
    &quot;b&quot;: &quot;2&quot;,
    &quot;c&quot;: &quot;0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c&quot;,
    &quot;length&quot;: 3
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-0be0a4dd-4ab1-457d-8846-92532b426326&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-08f0c6e6-0fa7-479b-a57a-077ad4e06ffa&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;전달한 값과 EOA 계정이 뜨는것을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-b4a24203-8405-420b-b446-89da8558e33b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 t 변수값을 확인하면 2개의 값이 더해진 3이 저장된것을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9b191b95-b389-4541-957b-7b1c6b7562b6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-cb6a07ba-5d47-4776-bfd9-10bc998fa6a4&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● Sample2에서 call과 delegatecall 차이 확인&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-33a82f2e-4e4a-46b5-b864-fb9a22e4e0b5&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0a13fd46-7386-4766-85d2-65bc652c0e13&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞의 방법은 매우 일반적인 방법입니다. 이제 call과 delegatecall을 이용하여 어떤 형태로 동작하는지 알아보겠습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-91f83eb0-2a06-4c25-a1ba-aeb529562fb4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-3bee00ad-2f24-4d13-8353-f34d34f3cf17&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;먼저, &lt;/span&gt;&lt;span&gt;&lt;b&gt;call&lt;/b&gt;&lt;/span&gt;&lt;span&gt;과 &lt;/span&gt;&lt;span&gt;&lt;b&gt;delegatecall&lt;/b&gt;&lt;/span&gt;&lt;span&gt;은 일반적으로 사용자 계정이 호출하는 형태는 아니고 컨트랙트에 의해서 호출하도록 도와주는 기능입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-81520b02-42ea-427c-81f5-1a23fc94cb65&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-5fa0a807-6d2d-446e-9107-d1ec9efe3c70&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; call &lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2f8a5a8b-e9b2-41bd-b08b-bdc2d02a15f7&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-fba37ac5-a490-452f-9653-f184307e5284&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;call을 확인하기 위해서는 Sample2에 해보된 callTest()를 호출합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-79ef4ecd-d0a6-4f67-8f54-f2f547956b2b&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/06Apl/btrKF0I0HAu/YAnkybVL5XX6kAQKEmyf3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/06Apl/btrKF0I0HAu/YAnkybVL5XX6kAQKEmyf3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/06Apl/btrKF0I0HAu/YAnkybVL5XX6kAQKEmyf3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F06Apl%2FbtrKF0I0HAu%2FYAnkybVL5XX6kAQKEmyf3K%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;536&quot; height=&quot;328&quot; data-origin-width=&quot;536&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-17f8b3cf-ec13-47f8-8741-5efe8c81afa8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-40c85865-0bcb-4ae9-b00a-6f00644714ed&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;callTest를 호출할 때 첫 번째 인자로 해당 컨트랙트가 호출할 컨트랙트 주소를 넣어줍니다. 그 이후의 인자는 호출할 컨트랙트가 전달받을 인자들입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-54d3b2c3-0d32-40f2-8061-66d03c02ab58&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e76e4979-0d8c-4c27-9a87-2bed84240cd6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서는 Sample2가 Sample1의 컨트랙트에 있는 test()를 호출하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-4a2d7727-579a-4c53-ae81-f1b46b691b3a&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FTDJ9/btrKF09453b/aiL0g8nOAHGkV9mPc331o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FTDJ9/btrKF09453b/aiL0g8nOAHGkV9mPc331o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FTDJ9/btrKF09453b/aiL0g8nOAHGkV9mPc331o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFTDJ9%2FbtrKF09453b%2FaiL0g8nOAHGkV9mPc331o0%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;773&quot; height=&quot;202&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-297eec2a-5dbc-471b-a84a-a1a5b6690399&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1661584663074&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;args&quot;: {
    &quot;a&quot;: &quot;4&quot;,
    &quot;b&quot;: &quot;5&quot;,
    &quot;c&quot;: &quot;0xbBF289D846208c16EDc8474705C748aff07732dB&quot;,
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7b88326b-1cf7-42dc-b7ca-8931c1fe6fd1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-195171e3-b60c-4cc9-802b-b3fe0997c9a6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;마찬가지로 logs 부분을 살쳐보면 a와 b는 callTest를 호출할 때 전달된 인자가 발생합니다. 그런데 c는 Sample2의 컨트랙트 주소가 표시됩니다. 그 이유는 Sample1로 배포된 컨트랙트를 Sample2가 호출했기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-ca90f092-2f20-4cd5-a158-1881b24aa3c8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-32cb122a-803a-45d9-989b-87929886be46&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;EOA가 Sample2의 컨트랙트를 호출, Sample2는 Sample1 호출하는 구조가 됩니다. 그럼 t의 값을 확인해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-f642c9e7-a170-4dc3-baa8-59558f50bd9e&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;681&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6pcQc/btrKHaRE1fm/QXyRf7ntrjLkM7E0EPmIlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6pcQc/btrKHaRE1fm/QXyRf7ntrjLkM7E0EPmIlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6pcQc/btrKHaRE1fm/QXyRf7ntrjLkM7E0EPmIlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6pcQc%2FbtrKHaRE1fm%2FQXyRf7ntrjLkM7E0EPmIlK%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;550&quot; height=&quot;681&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;681&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-ff0b93aa-f464-4a4b-aed5-e72ba055588f&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a78184d6-88ff-45c2-9ea8-276b871baa03&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Sample1로 배포된 컨트랙트의 t값만 바뀌게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-b1b48018-a27c-4546-9c87-8f4344566911&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-539188b4-b04d-43f8-aae9-951748d56ef8&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; delegatecall&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-230e69db-0080-41df-b177-72e159076fdf&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-a3e682c7-b067-4ed5-a26f-a30725d079b8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;delegatecall은 call이랑 다른 형태로 동작하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-8c707c47-b925-4796-9b00-4fac5b56874e&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PGHQF/btrKGPNJ0Ox/GOfFPp0IkUj6eKB7ZAIKXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PGHQF/btrKGPNJ0Ox/GOfFPp0IkUj6eKB7ZAIKXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PGHQF/btrKGPNJ0Ox/GOfFPp0IkUj6eKB7ZAIKXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPGHQF%2FbtrKGPNJ0Ox%2FGOfFPp0IkUj6eKB7ZAIKXK%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;538&quot; height=&quot;355&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;355&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aca08885-088e-4fe9-b1df-fff60ef6cb09&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-5817973a-f7c3-43d4-b22a-583fb1b49253&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번에는 Sample2로 배포된 컨트랙트에서 delegatecallTest를 호출해보겠습니다. callTest와 똑같이 넣어줍니다. 첫 번째 인자는 Sample1로 배포된 컨트랙즈 주소 두 번째와 세 번째 인자는 Sample2에서 호출할 test 함수로 전달할 인자를 넣어줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-8295734e-c0b6-4114-adae-00c1f74ee018&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-724bdadd-5cf5-4c18-976e-06028238391c&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번에는 앞의 테스트와 차이점을 보기위해 다른 수치를 넣고 트랜잭션을 발생시켜 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-aa782166-7f0b-4489-9822-a28b0f006bfa&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIeYJl/btrKHw1f4sl/ADYQ1blSIQoAdKxbSDZSN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIeYJl/btrKHw1f4sl/ADYQ1blSIQoAdKxbSDZSN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIeYJl/btrKHw1f4sl/ADYQ1blSIQoAdKxbSDZSN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIeYJl%2FbtrKHw1f4sl%2FADYQ1blSIQoAdKxbSDZSN1%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;773&quot; height=&quot;202&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-2731198e-4cba-44d7-b24b-33dc27479e59&quot;&gt;
&lt;pre id=&quot;code_1661584679243&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;args&quot;: {
    &quot;a&quot;: &quot;6&quot;,
    &quot;b&quot;: &quot;7&quot;,
    &quot;c&quot;: &quot;0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-9886a28d-a218-49de-9c09-938be47c2646&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-032c3c1a-0a4d-47bd-a424-dc91b2a23e48&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결과를 확인해보니 c가 Sample2의 컨트랙트가 아닌 Sample2를 호출한 EOA가 표시됩니다. 그리고 Sample1과 Sample2로 배포된 컨트랙트에서 t값을 확인해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-341b0477-c5ad-4b50-95a5-0c2d9e3fd432&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TSVyP/btrKF6PZRnd/Kz6YkZfC6uiBfkkS8jGM70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TSVyP/btrKF6PZRnd/Kz6YkZfC6uiBfkkS8jGM70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TSVyP/btrKF6PZRnd/Kz6YkZfC6uiBfkkS8jGM70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTSVyP%2FbtrKF6PZRnd%2FKz6YkZfC6uiBfkkS8jGM70%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;544&quot; height=&quot;552&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-d64aac46-ef38-405b-b5a3-c0a4972a4a65&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-041a9cbe-ef20-4799-b426-8ea788325614&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Sample1로 배포된 컨트랙트의 t가 아닌 Sample2로 배포된 컨트랙트의 t가 바뀝니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9ade860f-78c2-4e9a-b7ec-f2033e6663f3&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e17b2597-501a-431f-b9ad-24568ceeba16&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;delegatecall을 하게되면 msg.sender와 msg.value가 유지됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e70fc60c-3927-40fd-8972-a597f3ce10f7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-52e1be48-2c9b-43ac-9586-d656a7ce75a6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 context가 유지되게 됩니다. context 유지란 Sample2에서 Sample1을 delegatecall을 하게되면 Sample1 컨트랙트의 데이터를 수정하는것이 아닌 Sample2의 데이터를 수정하게 됩니다. 즉, 호출 당한 컨트랙트가 호출자 메모리 접근이 가능한 것을 의미합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-9e334105-6536-46d7-8308-bffb6c3827e8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;p id=&quot;SE-e2b029ab-55fe-4bc5-91d2-f51e8af70387&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Sample1로 배포된 컨트랙트 test()에서 t = a + b를 할 때 call을 하게되면 Sample1에 있는 t에 접근하여 값을 변경을 하고 delegatecall을 하게되면 context가 Sample2가 유지 되기 때문에 Sample2로 배포된 컨트랙트에 있는 t의 값이 변경되게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-893b6169-eccc-4b4a-b503-b739e45e0e4e&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 id=&quot;SE-c2d51bae-fa46-4807-9050-1d10c8741316&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;● call과 delegatecall 0.5에서 변경된 사항&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-661d3b4e-f6fc-4fa4-858c-aa76e2871f24&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-0de26d00-16cf-4e5a-acbc-3dedef213f3b&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;0.5 버전부터는 호출 성공/실패 유무와 반환된 데이터를 받아올 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-c0b6fcf0-a6b3-40bc-92d7-7bdeec9eed95&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 id=&quot;SE-bb005327-0d9a-4c99-abae-eebecd6efc91&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 0.5 버전 이후&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-6ce3f4a7-a1a1-4290-b95d-36ce9f671766&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-962ead5c-9daf-4dde-acc6-a51a374c2c0d&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661584701410&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(bool success, bytes memory data) = address(contractAddr).delegatecall(abi.encodeWithSignature(&quot;test(uint256,uint256)&quot;, to, value));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;SE-784bd56e-8a9f-4617-8c67-92a4bb28eac4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&amp;middot; 0.5 버전 이전&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-a9f8c0bb-2ed0-41de-a0c6-af9e300b6111&quot;&gt;
&lt;pre id=&quot;code_1661584707226&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool success = address(contractAddr).call(bytes4(sha3(&quot;test(uint256,uint256)&quot;)), to, value);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-7ad23beb-e297-4323-8483-445f4ff5564a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p id=&quot;SE-e6e61cb2-8f6b-42b1-995c-4d99f6e868cf&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;​&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SE-eb479c96-d0a5-49d4-b943-74c17bee73ca&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;div&gt;
&lt;p id=&quot;SE-693f84dc-cb12-46d5-8a08-d78af6a52afe&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개인적으로 solidity에서 가장 어려운 개념이지 않나 싶다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>Call</category>
      <category>delegatecall</category>
      <category>솔리디티</category>
      <category>이더리움</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/57</guid>
      <comments>https://meongae.tistory.com/57#entry57comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:18:46 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] keystore 파일에 대해서</title>
      <link>https://meongae.tistory.com/56</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더리움에서 account를 관리하는 방법은 여러가지 방법이 있습니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;1. private key&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;2. keystore&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;3. mnemonic&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실질적으로 우리는 private key만 있으면 되는데 private key가 노출되면 보안상에 매우 취약하므로 이를 대신해서 keystore(키스토어 파일) 또는 mnemonic(니모닉)의 형태로 대신 저장합니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;이번글에서는 파일형태로 저장되는 keystoer 파일에 대해서 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;여기서 private key가 중요한 이유는 transaction을 발생시킬 때, transaction을 발생시키는 address의 private key로 서명을 해야하기 때문에 매우 중요.&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;● 구조&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;keystore 파일은 이름과 내용이 특정 패턴에 의해서 생성됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 이름&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;keystore 파일의 이름은 생성 시간과 address를 포함하여 이름을 생성합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1542595321010-2008487325_code_0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #e57523;&quot;&gt;UTC&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;{&lt;/span&gt;생성시간&lt;span style=&quot;color: #666666;&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color: #a77f71;&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color: #666666;&quot;&gt;{&lt;/span&gt;address&lt;span style=&quot;color: #666666;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 내용&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 내용의 경우는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;private key&lt;/b&gt;를 만들기 위해 암호화된 데이터들을 포함합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1542595321010-2008487325_code_1&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661584405612&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
   &quot;id&quot;:&quot;bf74fcc7-8027-2c9d-b5d4-d65451fdfa35&quot;,
   &quot;version&quot;:3,
   &quot;crypto&quot;:{
      &quot;cipher&quot;:&quot;aes-128-ctr&quot;,
      &quot;cipherparams&quot;:{
         &quot;iv&quot;:&quot;059a40c98c81630c2bc9e0cd861d0a16&quot;
      },
      &quot;ciphertext&quot;:&quot;05fb430f572da8d3072571d46784435fe58843919310efc083c0fb19431bf3a7&quot;,
      &quot;kdf&quot;:&quot;pbkdf2&quot;,
      &quot;kdfparams&quot;:{
         &quot;c&quot;:10240,
         &quot;dklen&quot;:32,
         &quot;prf&quot;:&quot;hmac-sha256&quot;,
         &quot;salt&quot;:&quot;5dda813abd2b60ec414f89ecafeb50225e88ff858a4ead8652ef2eacd026be89&quot;
      },
      &quot;mac&quot;:&quot;8bac7c1e8b98dc1fe37d73430266a6c96586b90dec757f7cd28064702c446536&quot;
   },
   &quot;address&quot;:&quot;1c0e607bb9d657a7a4389a236b81a658a3f3b431&quot;,
   &quot;name&quot;:&quot;&quot;,
   &quot;meta&quot;:&quot;{}&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;keystore 파일을 열어보면 앞의 내용처럼 나타나게 되는데 크게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;id&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ve&lt;/b&gt;&lt;b&gt;r&lt;/b&gt;&lt;b&gt;sion&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;crypto&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;address&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;name&lt;/b&gt;&lt;span&gt;, meta 속성으로 이루어져 있습니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;crypto 내부에 있는 정보에 대해서 자세히 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;● crypto 속성&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;crypto는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;cipher&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;cipherparams&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ciphertext&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;kdf&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;kdfparams&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;mac&lt;/b&gt;으로 이루어져 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; cipher&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chiper는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;AES(&lt;/b&gt;&lt;b&gt;대칭 키 알고리즘)&lt;/b&gt;&amp;nbsp;=&amp;gt; 사용된 알고리즘은 aes-128-ctr&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; chipherparams&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AES에서 필요한 매개변수. 여기서 iv는 &quot;&lt;b&gt;초기화 벡터&lt;/b&gt;&quot; 입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; chiphertext&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AES(대칭 키 알고리즘)으로 암호화 시킬 데이터&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; kdf&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키를 유도하는데 사용하는 함수(해독하기 위해 필요한 값) =&amp;gt; 키 유도 함수(&lt;b&gt;key derivation function&lt;/b&gt;)&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; kdfparams&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kdf시 필요한 매개변수&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; mac&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호를 확인하기 위해 사용되는 코드&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;keystore 파일은 private key를 단순한 형태로 저장하는 것이 아닌 password로 암호화 하여 저장하는 방법이며 입력한 비밀번호를 검증하는 내용을 포함한 파일입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;● 시나리오&lt;/span&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; private key 생성&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cipherparams와 aiphertext를 cipher에 정의된 알고리즘으로 암호화 합니다. 여기서 나온 결과는 암호화된 private key 입니다. keystore 파일은 private key를 암호화된 형태로 관리됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 비밀번호로 보호&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 private key를 암호화 된 형태로 관리하기 때문에 해독에 필요한 해독 키를 사용합니다. 참고로 여기서 해독을 해야하는 이유는 해독한 후 keystore 파일을 생성할 때 입력한 비밀번호화 해독된 데이터를 SHA3-256으로 해싱한 후 mac과 같으면 정상적인 비밀번호다라고 private key를 받을 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kdf와 kdfparams를 이용하여 해독할 수 있는 키를 생성합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;여기서 해독된 결과를 주지않고 해독키만 반환하는 이유는 private key를 반환해버리면 keystore 파일만 가지고 해당 과정까지만 해서 private key가 노출되기 때문입니다.&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 검즘&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kdf로 해독 키를 받아온 후 입력한 비밀번호화 SHA3-256 알고리즘으로 해싱을 한 후 같으면 정상적으로 private key로 서명할 준비가 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/56</guid>
      <comments>https://meongae.tistory.com/56#entry56comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:14:20 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] block, transaction pool, state 각각 어디에 저장되는가</title>
      <link>https://meongae.tistory.com/55</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;thereum에서 block, transaction pool, state가 어디에 저장되는지 알아보도록 하겠습니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;먼저 block, state는 levelDB를 통해 저장이 됩니다. 근데 문득 그렇다면 transaction이 발생되고 pool에 저장된 tx들은 어디에 저장되는지 궁금해져서 테스트를 해보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; 2개의 account 생성&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_0&quot;&gt;
&lt;pre id=&quot;code_1661584081805&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.accounts
[&quot;0xe28674672b353d2d4c80435b610734e68bcd4362&quot;, &quot;0xbd83f6767a57da0c25b1437660adf43c3e1667be&quot;]

&amp;gt; eth.getBalance(eth.accounts[0])
75000000030000000000

&amp;gt; eth.getBalance(eth.accounts[1])
0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2개의 account를 생성한 후 transaction을 발생시킨 후 geth 프로그램을 종료했다가 다시 접속하여 tx pool을 확인해 보겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; tx 발생하기 전 tx pool 확인&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_1&quot;&gt;
&lt;pre id=&quot;code_1661584091037&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.pendingTransactions
[]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tx를 발생시키지 않았기 때문에 비어있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; tx 발생&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_2&quot;&gt;
&lt;pre id=&quot;code_1661584110758&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; personal.unlockAccount(eth.accounts[0], &quot;p&quot;)
true

&amp;gt; eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: 10000})
INFO [09-16|09:42:52] Submitted transaction                    fullhash=0x8360bedc21d02cd2c00e5dbc485949f6fee7cf3470e7bd94fe477d86c2152eff recipient=0xbd83f6767a57da0c25b1437660adf43c3e1667be
&quot;0x8360bedc21d02cd2c00e5dbc485949f6fee7cf3470e7bd94fe477d86c2152eff&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;geth에서는 account에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;lock&lt;/b&gt;이 되있기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;unlockAccount&lt;/b&gt;로 계정잠금을 풀어줘야 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; tx pool 확인&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_3&quot;&gt;
&lt;pre id=&quot;code_1661584119790&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.pendingTransactions
[{
    blockHash: null,
    blockNumber: null,
    from: &quot;0xe28674672b353d2d4c80435b610734e68bcd4362&quot;,
    gas: 90000,
    gasPrice: 18000000000,
    hash: &quot;0x8360bedc21d02cd2c00e5dbc485949f6fee7cf3470e7bd94fe477d86c2152eff&quot;,
    input: &quot;0x&quot;,
    nonce: 0,
    r: &quot;0x18e91ac9e352aa1353b31a4d544191e310a8fae75a1e8a63058a108a64c4f7b9&quot;,
    s: &quot;0x55c4028befc7fdc02e0b3b0230f7873ea017effd37b5e1a0a0aba93a2619fe93&quot;,
    to: &quot;0xbd83f6767a57da0c25b1437660adf43c3e1667be&quot;,
    transactionIndex: 0,
    v: &quot;0x5cd84&quot;,
    value: 10000
}]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;peding 중인 tx를 확인하니 방금 발생한 tx가 들어있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 geth 프로그램을 종료한 후 pending을 확인하면 메모리에 저장되는지 db에 저장되는지 알 수 있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; geth 프로그램 종료&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_4&quot;&gt;
&lt;pre id=&quot;code_1661584127376&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; exit
INFO [09-16|09:44:42] HTTP endpoint closed: http://0.0.0.0:8545
INFO [09-16|09:44:42] IPC endpoint closed: /Users/bagjeongtae/Desktop/geth_test/geth.ipc
INFO [09-16|09:44:42] Blockchain manager stopped
INFO [09-16|09:44:42] Stopping Ethereum protocol
INFO [09-16|09:44:42] Ethereum protocol stopped
INFO [09-16|09:44:42] Transaction pool stopped
INFO [09-16|09:44:42] Database closed                          database=/Users/bagjeongtae/Desktop/geth_test/geth/chaindata&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; geth 프로그램 다시시작&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_5&quot;&gt;
&lt;pre id=&quot;code_1661584139488&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vim start.sh
geth --networkid 1212121212 --maxpeers 3 --datadir $PWD --rpc --rpcport 8545 --rpcaddr &quot;0.0.0.0&quot; --rpccorsdomain &quot;*&quot; --rpcapi &quot;admin,db,eth,debug,miner,net,shh,txpool,personal,web3&quot; --port 30303 console&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;geth 시작명령어가 길기 때문에 매번치기 힘드므로 쉘 스크립트로 저장합니다. 머 물론 그냥 터미널에 복붙해도 됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_6&quot;&gt;
&lt;pre id=&quot;code_1661584146489&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ./start.sh
INFO [09-16|09:45:18] Starting peer-to-peer node               instance=Geth/v1.6.7-stable-ab5646c5/darwin-amd64/go1.9
INFO [09-16|09:45:18] Allocated cache and file handles         database=/Users/bagjeongtae/Desktop/geth_test/geth/chaindata cache=128 handles=1024
INFO [09-16|09:45:18] Initialised chain configuration          config=&quot;{ChainID: 190128 Homestead: 0 DAO: &amp;lt;nil&amp;gt; DAOSupport: false EIP150: &amp;lt;nil&amp;gt; EIP155: 0 EIP158: 0 Metropolis: &amp;lt;nil&amp;gt; Engine: unknown}&quot;
INFO [09-16|09:45:18] Disk storage enabled for ethash caches   dir=/Users/bagjeongtae/Desktop/geth_test/geth/ethash count=3
INFO [09-16|09:45:18] Disk storage enabled for ethash DAGs     dir=/Users/bagjeongtae/.ethash                       count=2
INFO [09-16|09:45:18] Initialising Ethereum protocol           versions=&quot;[63 62]&quot; network=1212121212
INFO [09-16|09:45:18] Loaded most recent local header          number=15 hash=8f3b47&amp;hellip;271944 td=2103872
INFO [09-16|09:45:18] Loaded most recent local full block      number=15 hash=8f3b47&amp;hellip;271944 td=2103872
INFO [09-16|09:45:18] Loaded most recent local fast block      number=15 hash=8f3b47&amp;hellip;271944 td=2103872
WARN [09-16|09:45:18] Blockchain not empty, fast sync disabled
INFO [09-16|09:45:18] Starting P2P networking
INFO [09-16|09:45:20] Mapped network port                      proto=udp extport=30303 intport=30303 interface=&quot;UPNP IGDv2-IP1&quot;
INFO [09-16|09:45:20] UDP listener up                          self=enode://d87594294e7e926cbc6de95361461550f5f7b726eeb93e7c609cb8bed0132296ef7f547c1f4284db1de8c3bc471688e0722d373aa882d0f43fdec427d5b4cc3c@121.161.16.47:30303
INFO [09-16|09:45:20] RLPx listener up                         self=enode://d87594294e7e926cbc6de95361461550f5f7b726eeb93e7c609cb8bed0132296ef7f547c1f4284db1de8c3bc471688e0722d373aa882d0f43fdec427d5b4cc3c@121.161.16.47:30303
INFO [09-16|09:45:20] IPC endpoint opened: /Users/bagjeongtae/Desktop/geth_test/geth.ipc
INFO [09-16|09:45:20] HTTP endpoint opened: http://0.0.0.0:8545
INFO [09-16|09:45:20] Mapped network port                      proto=tcp extport=30303 intport=30303 interface=&quot;UPNP IGDv2-IP1&quot;
Welcome to the Geth JavaScript console!

instance: Geth/v1.6.7-stable-ab5646c5/darwin-amd64/go1.9
coinbase: 0xe28674672b353d2d4c80435b610734e68bcd4362
at block: 15 (Sun, 16 Sep 2018 09:34:51 KST)
 datadir: /Users/bagjeongtae/Desktop/geth_test
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; tx pool 확인&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_7&quot;&gt;
&lt;pre id=&quot;code_1661584154856&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; eth.pendingTransactions
[]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램을 다시 시작하니 pending이 비어있습니다. 이것은 해당 데이터는 메모리에 저장된다는 의미입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&amp;middot; tx pool 직접확인&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;SEDOC-1537059200129-814227760_code_8&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661584167143&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; txpool
{
  content: {
    pending: {
      0xe28674672b353d2d4c80435b610734e68bcd4362: {
        0: {...}
      }
    },
    queued: {}
  },
  inspect: {
    pending: {
      0xe28674672b353d2d4c80435b610734e68bcd4362: {
        0: &quot;0xbd83f6767a57da0c25b1437660adf43c3e1667be: 10000 wei + 90000 &amp;times; 18000000000 gas&quot;
      }
    },
    queued: {}
  },
  status: {
    pending: 1,
    queued: 0
  },
  getContent: function(callback),
  getInspect: function(callback),
  getStatus: function(callback)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;txpool을 이용하면 좀 더 자세히 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>web3</category>
      <category>web3.js</category>
      <category>블록체인</category>
      <category>이더리움</category>
      <category>트랜잭션</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/55</guid>
      <comments>https://meongae.tistory.com/55#entry55comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:09:57 +0900</pubDate>
    </item>
    <item>
      <title>[ethereum] python으로 ethereum address 생성구현</title>
      <link>https://meongae.tistory.com/54</link>
      <description>&lt;div id=&quot;SEDOC-1535243270028-368617674_code_0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1661583940961&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/usr/bin/env python2

# pip install ecdsa
# pip install pysha3

from ecdsa import SigningKey, SECP256k1
import sha3

def checksum_encode(addr_str): # Takes a hex (string) address as input
    keccak = sha3.keccak_256()
    out = ''
    addr = addr_str.lower().replace('0x', '')
    keccak.update(addr.encode('ascii'))
    hash_addr = keccak.hexdigest()
    for i, c in enumerate(addr):
        if int(hash_addr[i], 16) &amp;gt;= 8:
            out += c.upper()
        else:
            out += c
    return '0x' + out

keccak = sha3.keccak_256()

priv = SigningKey.generate(curve=SECP256k1)
pub = priv.get_verifying_key().to_string()

keccak.update(pub)
address = keccak.hexdigest()[24:]

print(&quot;Private key:&quot;, priv.to_string())
print(&quot;Public key: &quot;, pub)
print(&quot;Address:    &quot;, checksum_encode(address))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해당 코드는 python으로 ethereum address를 생성하는 코드입니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;sha3이 python3에서 정상적으로 동작을 하지 않아 python2로 진행합니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;ethereum에서 사용하는 address는 private -&amp;gt; public을 거쳐서 address를 생성하게 됩니다.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;ECDSA&lt;/b&gt;&lt;/span&gt;&lt;span&gt;는 타원곡선알고리즘 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 address를 잊어버리더라도 private키를 알고있다면 address가 복구 가능한 이유가 이와같습니다. 또한 키스토어(keystore)파일로도 복구가 가능한데 keystore 파일은 private키를 생성해주는 파일입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>블록체인</category>
      <category>address</category>
      <category>ECDSA</category>
      <category>Ethereum</category>
      <category>keystore</category>
      <category>private</category>
      <category>Public</category>
      <category>타원곡선알고리즘</category>
      <author>멍개.</author>
      <guid isPermaLink="true">https://meongae.tistory.com/54</guid>
      <comments>https://meongae.tistory.com/54#entry54comment</comments>
      <pubDate>Sat, 27 Aug 2022 16:06:06 +0900</pubDate>
    </item>
  </channel>
</rss>