<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Crypto_Web_Developer.log</title>
        <link>https://velog.io/</link>
        <description>Blockchain Web Developer</description>
        <lastBuildDate>Thu, 10 Oct 2024 03:43:15 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Crypto_Web_Developer.log</title>
            <url>https://velog.velcdn.com/images/nft_sb/profile/6e27d971-2aef-4f25-9040-a4fcb58f7caa/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Crypto_Web_Developer.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/nft_sb" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Next.js 소스코드 배포 방법]]></title>
            <link>https://velog.io/@nft_sb/Next.js-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-%EB%B0%B0%ED%8F%AC-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@nft_sb/Next.js-%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-%EB%B0%B0%ED%8F%AC-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Thu, 10 Oct 2024 03:43:15 GMT</pubDate>
            <description><![CDATA[<p>Ubuntu 22.04 기반 리눅스 서버에 Next.js 애플리케이션을 배포하는 방법을 단계별로 설명하겠습니다. 이 과정에서는 PM2와 Nginx를 사용하여 Next.js 애플리케이션을 프로덕션 환경에서 실행하는 방법을 다룹니다.</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/b540cc25-2f8f-421b-9235-c74a38679494/image.png" alt=""></p>
<h2 id="1-nextjs-애플리케이션-설정">1. Next.js 애플리케이션 설정</h2>
<h3 id="11-프로젝트-클론">1.1 프로젝트 클론</h3>
<p>GitHub 또는 다른 리포지토리에서 프로젝트를 클론합니다.</p>
<pre><code class="language-bash">git clone https://github.com/username/repository.git
cd repository</code></pre>
<h3 id="12-종속성-설치">1.2 종속성 설치</h3>
<p>프로젝트 디렉토리로 이동하여 종속성을 설치합니다.</p>
<pre><code class="language-bash">npm install</code></pre>
<h3 id="13-nextjs-애플리케이션-빌드">1.3 Next.js 애플리케이션 빌드</h3>
<p>프로덕션 빌드를 생성합니다.</p>
<pre><code class="language-bash">npm run build</code></pre>
<h3 id="14-애플리케이션-시작">1.4 애플리케이션 시작</h3>
<p>PM2를 사용하여 애플리케이션을 백그라운드에서 실행합니다.</p>
<pre><code class="language-bash">pm2 start npm --name &quot;nextjs-app&quot; -- start
pm2 save
pm2 startup</code></pre>
<h2 id="2-nginx-설정">2. Nginx 설정</h2>
<h3 id="21-nginx-설치">2.1 Nginx 설치</h3>
<p>Nginx를 설치합니다.</p>
<pre><code class="language-bash">sudo apt install nginx -y</code></pre>
<h3 id="22-nginx-구성-파일-설정">2.2 Nginx 구성 파일 설정</h3>
<p>Nginx 구성 파일을 편집하여 Next.js 애플리케이션을 역방향 프록시로 설정합니다.</p>
<pre><code class="language-bash">sudo nano /etc/nginx/sites-available/default</code></pre>
<p>파일 내용을 다음과 같이 수정합니다:</p>
<pre><code class="language-nginx">server {
    listen 80;
    server_name your_domain_or_ip;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection &#39;upgrade&#39;;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}</code></pre>
<h3 id="23-nginx-설정-테스트-및-재시작">2.3 Nginx 설정 테스트 및 재시작</h3>
<p>Nginx 설정이 올바른지 테스트하고 Nginx를 재시작합니다.</p>
<pre><code class="language-bash">sudo nginx -t
sudo systemctl restart nginx</code></pre>
<h2 id="3-방화벽-설정">3. 방화벽 설정</h2>
<h3 id="31-방화벽-설정">3.1 방화벽 설정</h3>
<p>UFW를 사용하여 필요한 포트를 엽니다.</p>
<pre><code class="language-bash">sudo ufw allow &#39;Nginx Full&#39;
sudo ufw enable</code></pre>
<h2 id="4-도메인-설정-선택-사항">4. 도메인 설정 (선택 사항)</h2>
<h3 id="41-도메인-연결">4.1 도메인 연결</h3>
<p>도메인을 사용하는 경우, DNS 설정에서 도메인을 서버의 IP 주소에 매핑합니다.</p>
<h3 id="42-ssl-인증서-설정-lets-encrypt">4.2 SSL 인증서 설정 (Let’s Encrypt)</h3>
<p>HTTPS를 설정하기 위해 Let’s Encrypt를 사용하여 SSL 인증서를 설치합니다.</p>
<pre><code class="language-bash">sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d your_domain</code></pre>
<p>인증서 갱신을 자동화합니다.</p>
<pre><code class="language-bash">sudo certbot renew --dry-run</code></pre>
<h2 id="결론">결론</h2>
<p>이제 Next.js 애플리케이션이 Ubuntu 22.04 서버에서 Nginx와 PM2를 사용하여 프로덕션 환경에서 실행되고 있습니다. 애플리케이션을 배포할 때마다 코드를 푸시하고, 서버에서 Git을 사용하여 코드를 업데이트한 후 <code>npm run build</code>와 <code>pm2 restart nextjs-app</code>을 실행하여 새로운 빌드를 반영할 수 있습니다.</p>
<p>이 글이 Next.js 애플리케이션을 배포하는 데 도움이 되기를 바랍니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Ubuntu 20.04에서 Nginx 설치 및 설정하기_02]]></title>
            <link>https://velog.io/@nft_sb/Ubuntu-20.04%EC%97%90%EC%84%9C-Nginx-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B002</link>
            <guid>https://velog.io/@nft_sb/Ubuntu-20.04%EC%97%90%EC%84%9C-Nginx-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B002</guid>
            <pubDate>Thu, 10 Oct 2024 03:35:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nft_sb/post/bca7336c-bd7e-4f99-817f-c76898f630a4/image.png" alt=""></p>
<hr>
<p>이 포스트는 프로젝트를 배포하는 과정에서 참고한 여러 개의 포스트를 종합한 글입니다. 이번 글에서는 Nginx를 활용하여 Next.js 애플리케이션을 배포하는 방법을 상세히 설명합니다. 특히 SSL 인증서 설정과 Reverse Proxy 설정을 통해 보안성과 성능을 강화하는 방법을 다룹니다.</p>
<h2 id="목차">목차</h2>
<ol>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">Nginx 역할</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">SSL 인증서 파일 생성</a><ul>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">.pfx 파일로 .crt, .rsa 파일 생성하기</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">인증서 정확성 검증</a></li>
</ul>
</li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">/etc/nginx/nginx.conf 파일 설정</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">/etc/nginx/conf.d/domain.conf 설정</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">Next.js 프로젝트를 4000번 포트로 실행</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">Nginx 실행</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">Nginx 관련 명령어</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_02-3e6607ac9c474f73b58a64c6b4622040?pvs=21">레퍼런스</a></li>
</ol>
<hr>
<h2 id="nginx-역할">Nginx 역할</h2>
<p>Nginx는 고성능의 웹 서버이자 Reverse Proxy 서버로, 다양한 용도로 활용됩니다. 이번 프로젝트에서는 Next.js와 함께 Nginx를 사용하여 다음과 같은 역할을 수행합니다:</p>
<ul>
<li><strong>웹 서버 구축</strong>: Next.js는 JavaScript 기반의 서버리스 프레임워크로, 자체적으로 서버 기능을 제공하지 않습니다. 따라서 Nginx가 Next.js 애플리케이션을 실행해주는 역할을 합니다.</li>
<li><strong>클라이언트 요청 처리</strong>: 사용자가 브라우저의 주소창에 URL을 입력하면 Nginx가 중간에서 요청을 받아 Linux 환경(OCI)에서 실행 중인 Next.js 프로젝트로 전달합니다.</li>
<li><strong>정적 파일 제공</strong>: 클라이언트로부터의 요청에 맞는 정적 파일을 응답해주는 HTTP Web Server로 활용됩니다.</li>
<li><strong>Reverse Proxy 및 로드 밸런서</strong>: Nginx를 Reverse Proxy 서버로 설정하여 WAS(Web Application Server)의 부하를 줄이고, 로드 밸런싱을 통해 성능을 최적화할 수 있습니다.</li>
</ul>
<p>!<a href="https://velog.velcdn.com/images/loocia1910/post/36580837-83d8-47c6-8a4b-9e6c566edafe/image.png">https://velog.velcdn.com/images/loocia1910/post/36580837-83d8-47c6-8a4b-9e6c566edafe/image.png</a></p>
<h2 id="ssl-인증서-파일-생성">SSL 인증서 파일 생성</h2>
<p>보안성을 강화하기 위해 SSL 인증서를 설정합니다. 이번 프로젝트에서는 회사에서 구매한 <code>.pfx</code> 파일을 이용하여 SSL 설정을 진행하였습니다.</p>
<h3 id="pfx-파일로-crt-rsa-파일-생성하기">.pfx 파일로 .crt, .rsa 파일 생성하기</h3>
<p><code>.pfx</code> 파일을 사용하여 <code>.crt</code>와 <code>.rsa</code> 키 파일을 생성합니다.</p>
<pre><code class="language-bash">openssl pkcs12 -in /usr/local/nginx/ssl/xxx.pfx -clcerts -nokeys -out /usr/local/nginx/ssl/xxx.crt
openssl pkcs12 -in /usr/local/nginx/ssl/xxx.pfx -nocerts -nodes -out /usr/local/nginx/ssl/xxx.rsa
</code></pre>
<h3 id="인증서-정확성-검증">인증서 정확성 검증</h3>
<p>443 포트가 사용 중인 경우, 프로세스를 종료하고 인증서의 정확성을 검증합니다.</p>
<pre><code class="language-bash">openssl s_server -www -accept 443 -cert /usr/local/nginx/ssl/xxx.crt -key /usr/local/nginx/ssl/xxx.rsa
</code></pre>
<h2 id="etcnginxnginxconf-파일-설정">/etc/nginx/nginx.conf 파일 설정</h2>
<p>Nginx의 메인 설정 파일인 <code>nginx.conf</code>를 수정하여 기본 설정을 적용합니다. 이 파일은 최상위 Nginx 실행 파일로, 다른 설정 파일들을 포함하고 있습니다.</p>
<pre><code>// /etc/nginx/nginx.conf

user  root;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice; // nginx 에러 로그 위치

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  &#39;$remote_addr - $remote_user [$time_local] &quot;$request&quot; &#39;
                      &#39;$status $body_bytes_sent &quot;$http_referer&quot; &#39;
                      &#39;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&#39;;

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    autoindex       on;
    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf; // 하위 conf 파일들 포함
}
</code></pre><h2 id="etcnginxconfddomainconf-설정">/etc/nginx/conf.d/domain.conf 설정</h2>
<p>서버 블록(Server Block)을 설정하여 도메인 별로 Nginx를 구성합니다. 이 설정 파일은 <code>conf.d</code> 디렉토리에 위치하며, 도메인 이름으로 파일명을 지정하는 것이 좋습니다.</p>
<pre><code>// /etc/nginx/conf.d/domain.conf

server {
    listen 80;
    listen [::]:80;
    server_name www.domain.com domain.com; // 도메인 명

    // 301 리다이렉트를 통해 HTTP를 HTTPS로 전환
    return 301 https://$host$request_uri;
}

server {
    listen [::]:443 ssl;
    listen 443 ssl;

    server_name www.domain.com domain.com;
    root /www/domain_2022/; // 프로젝트 디렉토리

    location / {
        proxy_pass &lt;http://localhost:4000&gt;; // 4000번 포트에서 실행 중인 Next.js 프로젝트로 연결
    }

    ssl on;
    ssl_certificate /etc/ssl/domain.crt;  // 생성한 SSL 인증서
    ssl_certificate_key /etc/ssl/domain.rsa; // 생성한 SSL 키
    ssl_prefer_server_ciphers on;
}
</code></pre><h2 id="nextjs-프로젝트를-4000번-포트로-실행">Next.js 프로젝트를 4000번 포트로 실행</h2>
<p>Next.js 애플리케이션을 특정 포트(여기서는 4000번)에서 실행하여 Nginx가 이를 프록시하도록 설정합니다. <code>package.json</code> 파일을 수정하여 포트를 설정합니다.</p>
<pre><code class="language-json">// package.json

{
  &quot;name&quot;: &quot;homepage-2022&quot;,
  &quot;version&quot;: &quot;0.1.0&quot;,
  &quot;private&quot;: true,
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;next dev&quot;,
    &quot;build&quot;: &quot;next build&quot;,
    &quot;start&quot;: &quot;next start -p ${PORT:-4000}&quot;, // 4000번 포트에서 실행
    &quot;lint&quot;: &quot;next lint&quot;
  },
  &quot;dependencies&quot;: {
    // 생략
  },
  &quot;devDependencies&quot;: {
    // 생략
  }
}
</code></pre>
<h3 id="프로젝트-실행-절차">프로젝트 실행 절차</h3>
<ol>
<li>프로젝트 디렉토리로 이동합니다.</li>
<li>프로젝트를 빌드합니다.</li>
<li>프로젝트를 백그라운드에서 실행합니다.</li>
</ol>
<pre><code class="language-bash">cd /www/domain_2022/
npm install
npm run build
npm run start &amp;
</code></pre>
<h2 id="nginx-실행">Nginx 실행</h2>
<p>Nginx는 어느 디렉토리에서든 실행할 수 있습니다. 설정이 완료된 후, Nginx 서비스를 시작합니다.</p>
<pre><code class="language-bash">sudo systemctl start nginx
</code></pre>
<h2 id="nginx-관련-명령어">Nginx 관련 명령어</h2>
<p>Nginx 서비스는 <code>systemctl</code> 명령어를 통해 관리할 수 있습니다. 주요 명령어는 다음과 같습니다:</p>
<pre><code class="language-bash"># 시작
sudo systemctl start nginx

# 종료
sudo systemctl stop nginx

# 재시작
sudo systemctl restart nginx

# 리로드 (변경된 설정을 적용하는 경우 사용. 기존 연결을 끊지 않음.)
sudo systemctl reload nginx

# 기본적으로 서버 시작 시 Nginx가 자동으로 실행되는데, 이를 막고 싶은 경우
sudo systemctl disable nginx

# 서버 시작 시 자동으로 Nginx를 실행하고 싶은 경우
sudo systemctl enable nginx
</code></pre>
<h2 id="레퍼런스">레퍼런스</h2>
<ul>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04">How To Install Nginx on Ubuntu 20.04</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04">How To Secure Nginx with Let’s Encrypt on Ubuntu 20.04</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-nginx-with-http-2-support-on-ubuntu-20-04">How To Set Up Nginx with HTTP/2 Support on Ubuntu 20.04</a></li>
</ul>
<hr>
<p>이 글이 Ubuntu 20.04에서 Nginx를 설치하고 설정하는 데 도움이 되었기를 바랍니다. 추가적인 질문이나 도움이 필요하시면 댓글로 남겨주세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Ubuntu 20.04에서 Nginx 설치 및 설정하기_01]]></title>
            <link>https://velog.io/@nft_sb/Ubuntu-20.04%EC%97%90%EC%84%9C-Nginx-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@nft_sb/Ubuntu-20.04%EC%97%90%EC%84%9C-Nginx-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 10 Oct 2024 03:32:23 GMT</pubDate>
            <description><![CDATA[<hr>
<p>이 포스트는 프로젝트를 배포하는 과정에서 참고한 여러 개의 포스트를 종합한 글입니다. Ubuntu 20.04 환경에서 Nginx를 설치하고 설정하는 방법을 단계별로 안내합니다. 기본 설치부터 방화벽 설정, 서버 블록 구성, HTTPS 적용 및 HTTP/2 설정까지 다룹니다.</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/6c0f155c-1fa0-4eaf-8a85-f939ce14e3a3/image.png" alt=""></p>
<h2 id="목차">목차</h2>
<ol>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_01-07188db0015540999e5fb91f2da4d98b?pvs=21">Nginx 설치</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_01-07188db0015540999e5fb91f2da4d98b?pvs=21">방화벽 설정</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_01-07188db0015540999e5fb91f2da4d98b?pvs=21">Nginx 상태 체크</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_01-07188db0015540999e5fb91f2da4d98b?pvs=21">Nginx 프로세스 관리 명령어</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_01-07188db0015540999e5fb91f2da4d98b?pvs=21">서버 블록 설정</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_01-07188db0015540999e5fb91f2da4d98b?pvs=21">HTTPS 적용</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_01-07188db0015540999e5fb91f2da4d98b?pvs=21">HTTP/2 적용</a></li>
<li><a href="https://www.notion.so/Ubuntu-20-04-Nginx-_01-07188db0015540999e5fb91f2da4d98b?pvs=21">레퍼런스</a></li>
</ol>
<hr>
<h2 id="nginx-설치">Nginx 설치</h2>
<p>먼저, 시스템 패키지를 업데이트하고 Nginx를 설치합니다.</p>
<pre><code class="language-bash">sudo apt update
sudo apt install nginx
</code></pre>
<p>설치가 완료되면 Nginx 서비스가 자동으로 시작됩니다.</p>
<h2 id="방화벽-설정">방화벽 설정</h2>
<p>Ubuntu의 기본 방화벽인 UFW(Uncomplicated Firewall)를 사용하여 Nginx 트래픽을 허용합니다. 먼저, UFW에서 사용 가능한 애플리케이션을 확인합니다.</p>
<pre><code class="language-bash">sudo ufw app list
</code></pre>
<p>위 명령을 실행하면 다음과 같은 리스트가 출력됩니다:</p>
<pre><code class="language-bash">Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH
</code></pre>
<p>각 설정의 의미는 다음과 같습니다:</p>
<ul>
<li><strong>Nginx HTTP</strong>: 포트 80번만 허용</li>
<li><strong>Nginx HTTPS</strong>: 포트 443번만 허용</li>
<li><strong>Nginx Full</strong>: 포트 80, 443번 모두 허용</li>
</ul>
<p>Nginx HTTP 트래픽을 허용하려면 다음 명령어를 사용합니다:</p>
<pre><code class="language-bash">sudo ufw allow &#39;Nginx HTTP&#39;
</code></pre>
<p>방화벽 상태를 확인하여 설정이 제대로 적용되었는지 확인합니다:</p>
<pre><code class="language-bash">sudo ufw status
</code></pre>
<pre><code class="language-bash">Status: active

To                         Action      From
--                         ------      ----
Nginx HTTP                 ALLOW       Anywhere
Nginx HTTP (v6)            ALLOW       Anywhere (v6)
</code></pre>
<p>만약 방화벽이 <code>inactive</code> 상태라면, 아래 명령어로 활성화합니다:</p>
<pre><code class="language-bash">sudo ufw enable
</code></pre>
<h2 id="nginx-상태-체크">Nginx 상태 체크</h2>
<p>Nginx가 정상적으로 실행 중인지 확인하기 위해 상태를 체크합니다:</p>
<pre><code class="language-bash">systemctl status nginx
</code></pre>
<p>출력 예시는 다음과 같습니다:</p>
<pre><code class="language-bash">● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2022-04-20 09:03:47 UTC; 24h ago
       Docs: man:nginx(8)
   Main PID: 20596 (nginx)
      Tasks: 2 (limit: 1147)
     Memory: 5.4M
     CGroup: /system.slice/nginx.service
             ├─20596 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
             └─20597 nginx: worker process
</code></pre>
<p>또한, 브라우저의 주소창에 서버의 IP 주소나 도메인 이름을 입력하여 기본 Nginx 랜딩 페이지가 표시되는지 확인합니다:</p>
<p>!<a href="https://cdn.jsdelivr.net/gh/jaehyeon48/jaehyeon48.github.io@master/assets/images/nginx/configure-nginx-on-ubuntu-2004/welcome_to_nginx.png">https://cdn.jsdelivr.net/gh/jaehyeon48/jaehyeon48.github.io@master/assets/images/nginx/configure-nginx-on-ubuntu-2004/welcome_to_nginx.png</a></p>
<p>위 랜딩 페이지가 표시된다면 Nginx가 정상적으로 동작하고 있는 것입니다.</p>
<h2 id="nginx-프로세스-관리-명령어">Nginx 프로세스 관리 명령어</h2>
<p>Nginx 서비스는 <code>systemctl</code> 명령어를 통해 관리할 수 있습니다. 주요 명령어는 다음과 같습니다:</p>
<pre><code class="language-bash"># 시작
sudo systemctl start nginx

# 종료
sudo systemctl stop nginx

# 재시작
sudo systemctl restart nginx

# 리로드 (변경된 설정을 적용하는 경우 사용. 기존 연결을 끊지 않음.)
sudo systemctl reload nginx

# 기본적으로 서버 시작 시 Nginx가 자동으로 실행되는데, 이를 막고 싶은 경우
sudo systemctl disable nginx

# 서버 시작 시 자동으로 Nginx를 실행하고 싶은 경우
sudo systemctl enable nginx
</code></pre>
<h2 id="서버-블록-설정">서버 블록 설정</h2>
<p>Nginx에서는 서버 블록(Server Block)을 통해 여러 도메인을 관리할 수 있습니다. 서버 블록 설정 절차는 다음과 같습니다:</p>
<h3 id="1-디렉토리-생성">1. 디렉토리 생성</h3>
<p>도메인 별 웹 파일을 저장할 디렉토리를 생성합니다.</p>
<pre><code class="language-bash">sudo mkdir -p /var/www/도메인이름/html
</code></pre>
<h3 id="2-소유자-설정">2. 소유자 설정</h3>
<p>생성한 디렉토리의 소유자를 현재 사용자로 변경합니다.</p>
<pre><code class="language-bash">sudo chown -R $USER:$USER /var/www/도메인이름/html
</code></pre>
<h3 id="3-권한-설정">3. 권한 설정</h3>
<p>디렉토리의 권한을 설정하여 웹 서버가 파일에 접근할 수 있도록 합니다.</p>
<pre><code class="language-bash">sudo chmod -R 755 /var/www/도메인이름
</code></pre>
<h3 id="4-indexhtml-생성">4. <code>index.html</code> 생성</h3>
<p>웹 페이지의 기본 파일을 생성합니다.</p>
<pre><code class="language-bash">sudo vi /var/www/도메인이름/html/index.html
</code></pre>
<p><code>index.html</code> 파일에 간단한 HTML 코드를 입력합니다.</p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;Welcome to Nginx!&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Success! The Nginx server block is working!&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3 id="5-서버-블록-생성">5. 서버 블록 생성</h3>
<p>새로운 서버 블록 설정 파일을 생성합니다.</p>
<pre><code class="language-bash">sudo vi /etc/nginx/sites-available/도메인이름
</code></pre>
<p>아래 내용을 입력합니다:</p>
<pre><code>server {
    listen 80;
    listen [::]:80;

    root /var/www/도메인이름/html;
    index index.html index.htm index.nginx-debian.html;

    server_name 도메인이름 www.도메인이름;

    location / {
        try_files $uri $uri/ =404;
    }
}
</code></pre><h3 id="6-심볼릭-링크-생성">6. 심볼릭 링크 생성</h3>
<p>서버 블록 설정을 활성화하기 위해 심볼릭 링크를 생성합니다.</p>
<pre><code class="language-bash">sudo ln -s /etc/nginx/sites-available/도메인이름 /etc/nginx/sites-enabled/
</code></pre>
<h3 id="7-nginxconf-파일-설정">7. <code>nginx.conf</code> 파일 설정</h3>
<p>Nginx의 메인 설정 파일을 수정하여 서버 이름 해시 버킷 크기를 늘립니다.</p>
<pre><code class="language-bash">sudo vi /etc/nginx/nginx.conf
</code></pre>
<p><code>http</code> 블록 내에 다음 내용을 추가합니다:</p>
<pre><code>http {
    ...
    server_names_hash_bucket_size 64;
    ...
}
</code></pre><h3 id="8-설정-파일-문법-오류-검사">8. 설정 파일 문법 오류 검사</h3>
<p>Nginx 설정 파일에 문법 오류가 없는지 확인합니다.</p>
<pre><code class="language-bash">sudo nginx -t
</code></pre>
<h3 id="9-nginx-재시작">9. Nginx 재시작</h3>
<p>설정이 정상이라면 Nginx를 재시작하여 변경 사항을 적용합니다.</p>
<pre><code class="language-bash">sudo systemctl restart nginx
</code></pre>
<p>이제 브라우저의 주소창에 <code>http://도메인이름</code>을 입력하면 생성한 <code>index.html</code>의 내용이 표시됩니다.</p>
<h2 id="https-적용">HTTPS 적용</h2>
<h3 id="📌-https를-적용하고자-하는-경우">📌 HTTPS를 적용하고자 하는 경우</h3>
<ul>
<li>반드시 등록된 도메인이 있어야 합니다.</li>
<li>도메인에 대한 A 레코드가 존재해야 합니다.</li>
<li>위에서 설정했던 서버 블록 설정이 완료되어 있어야 합니다.</li>
</ul>
<h3 id="1-certbot-설치">1. Certbot 설치</h3>
<p>Certbot은 Let&#39;s Encrypt의 SSL 인증서를 쉽게 발급받고 설정할 수 있게 도와줍니다.</p>
<pre><code class="language-bash">sudo apt install certbot python3-certbot-nginx
</code></pre>
<h3 id="2-방화벽에서-https-허용">2. 방화벽에서 HTTPS 허용</h3>
<p>HTTPS 트래픽을 허용하고 기존의 HTTP만 허용 설정을 제거합니다.</p>
<pre><code class="language-bash">sudo ufw allow &#39;Nginx Full&#39;  # HTTP와 HTTPS 모두 허용
sudo ufw delete allow &#39;Nginx HTTP&#39;  # 기존의 HTTP만 허용 설정 제거
</code></pre>
<h3 id="3-ssl-인증서-발급">3. SSL 인증서 발급</h3>
<p>Certbot을 사용하여 SSL 인증서를 발급받고 Nginx 설정을 자동으로 업데이트합니다.</p>
<pre><code class="language-bash">sudo certbot --nginx -d 도메인이름 -d www.도메인이름
</code></pre>
<p>처음 실행 시 이메일 입력 및 약관 동의가 요구됩니다. 인증서 발급이 완료되면 HTTPS 설정이 자동으로 적용되고 Nginx가 재시작됩니다.</p>
<p>출력 예시는 다음과 같습니다:</p>
<pre><code>IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2020-08-18. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the &quot;certonly&quot; option. To non-interactively renew *all* of
   your certificates, run &quot;certbot renew&quot;
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let&#39;s Encrypt:   &lt;https://letsencrypt.org/donate&gt;
   Donating to EFF:                    &lt;https://eff.org/donate-le&gt;
</code></pre><h3 id="4-certbot-자동-갱신-확인하기">4. Certbot 자동 갱신 확인하기</h3>
<p>Let&#39;s Encrypt의 인증서는 90일 동안 유효합니다. Certbot은 자동으로 인증서를 갱신할 수 있도록 타이머를 설정합니다.</p>
<p>타이머 상태를 확인하려면 다음 명령어를 사용합니다:</p>
<pre><code class="language-bash">sudo systemctl status certbot.timer
</code></pre>
<p>출력 예시는 다음과 같습니다:</p>
<pre><code class="language-bash">● certbot.timer - Run certbot twice daily
     Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Mon 2020-05-04 20:04:36 UTC; 2 weeks 1 days ago
    Trigger: Thu 2020-05-21 05:22:32 UTC; 9h left
   Triggers: ● certbot.service
</code></pre>
<p>자동 갱신 과정을 테스트하려면 다음 명령어를 실행합니다:</p>
<pre><code class="language-bash">sudo certbot renew --dry-run
</code></pre>
<h2 id="http2-적용">HTTP/2 적용</h2>
<h3 id="📌-http2를-적용하고자-하는-경우">📌 HTTP/2를 적용하고자 하는 경우</h3>
<ul>
<li>반드시 등록된 도메인과 서버에 TLS 설정이 적용되어 있어야 합니다.</li>
</ul>
<h3 id="1-http2-옵션-켜기">1. HTTP/2 옵션 켜기</h3>
<p>서버 블록 설정 파일을 열고 <code>listen</code> 지시에 <code>http2</code> 옵션을 추가합니다.</p>
<pre><code class="language-bash">sudo vi /etc/nginx/sites-enabled/도메인이름
</code></pre>
<p>아래와 같이 수정합니다:</p>
<pre><code>server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2 ipv6only=on;

    root /var/www/도메인이름/html;
    index index.html index.htm index.nginx-debian.html;

    server_name 도메인이름 www.도메인이름;

    location / {
        try_files $uri $uri/ =404;
    }
}
</code></pre><p>설정 파일 문법을 다시 한 번 검사합니다:</p>
<pre><code class="language-bash">sudo nginx -t
</code></pre>
<h3 id="2-안전하지-않은-cipher-suite-제거">2. 안전하지 않은 Cipher Suite 제거</h3>
<p>보안 강화를 위해 안전하지 않은 Cipher Suite를 제거합니다.</p>
<pre><code class="language-bash">sudo vi /etc/nginx/sites-enabled/도메인이름
</code></pre>
<p><code>include /etc/letsencrypt/options-ssl-nginx.conf;</code> 라인을 주석 처리하거나 제거하고, 아래와 같이 <code>ssl_ciphers</code>를 설정합니다:</p>
<pre><code>ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
</code></pre><p>만약 self-signed 인증서를 사용하는 경우, 추가적인 설정이 필요할 수 있습니다:</p>
<pre><code class="language-bash">sudo nano /etc/nginx/snippets/ssl-params.conf
</code></pre>
<p>기존 <code>ssl_ciphers</code> 설정을 아래 내용으로 변경합니다:</p>
<pre><code>ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
</code></pre><p>설정이 완료되면 Nginx 설정을 다시 로드합니다:</p>
<pre><code class="language-bash">sudo systemctl reload nginx
</code></pre>
<h3 id="3-hstshttp-strict-transport-security-설정하기">3. HSTS(HTTP Strict Transport Security) 설정하기</h3>
<p>HSTS를 통해 브라우저가 반드시 HTTPS를 사용하도록 강제할 수 있습니다.</p>
<pre><code class="language-bash">sudo vi /etc/nginx/sites-enabled/도메인이름
</code></pre>
<p><code>server</code> 블록 내에 아래 라인을 추가합니다:</p>
<pre><code>add_header Strict-Transport-Security &quot;max-age=31536000&quot; always;
</code></pre><p>서브도메인에도 HSTS를 적용하려면 <code>includeSubDomains</code> 값을 추가합니다:</p>
<pre><code>add_header Strict-Transport-Security &quot;max-age=31536000; includeSubDomains&quot; always;
</code></pre><p>설정을 적용하기 위해 Nginx를 다시 로드합니다:</p>
<pre><code class="language-bash">sudo systemctl reload nginx
</code></pre>
<h2 id="레퍼런스">레퍼런스</h2>
<ul>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04">How To Install Nginx on Ubuntu 20.04</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04">How To Secure Nginx with Let’s Encrypt on Ubuntu 20.04</a></li>
<li><a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-nginx-with-http-2-support-on-ubuntu-20-04">How To Set Up Nginx with HTTP/2 Support on Ubuntu 20.04</a></li>
</ul>
<hr>
<p>이 글이 Ubuntu 20.04에서 Nginx를 설치하고 설정하는 데 도움이 되었기를 바랍니다. 추가적인 질문이나 도움이 필요하시면 댓글로 남겨주세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Docker 명령어를 `sudo` 없이 사용하기]]></title>
            <link>https://velog.io/@nft_sb/Docker-%EB%AA%85%EB%A0%B9%EC%96%B4%EB%A5%BC-sudo-%EC%97%86%EC%9D%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@nft_sb/Docker-%EB%AA%85%EB%A0%B9%EC%96%B4%EB%A5%BC-sudo-%EC%97%86%EC%9D%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 10 Oct 2024 03:19:40 GMT</pubDate>
            <description><![CDATA[<h3 id="docker-명령어를-sudo-없이-사용하기"><strong>Docker 명령어를 <code>sudo</code> 없이 사용하기</strong></h3>
<p>개발 환경에서 Docker는 필수 도구가 되었지만, 매번 <code>sudo</code>를 사용하여 Docker 명령어를 실행하는 것은 불편할 수 있습니다. 이 글에서는 <code>sudo</code> 없이 Docker 명령어를 사용하기 위한 방법을 설명하고, 추가적인 권한 설정 및 오류 해결 방안을 공유하겠습니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/b3cc1ea9-651f-470f-bd96-202e040a2c50/image.png" alt=""></p>
<h3 id="docker-권한-문제"><strong>Docker 권한 문제</strong></h3>
<p>기본적으로 Docker 데몬은 <code>root</code> 권한으로 실행되며, <code>docker</code> 명령어를 사용하려면 <code>sudo</code> 권한이 필요합니다. Docker는 <code>/var/run/docker.sock</code>이라는 Unix 도메인 소켓을 통해 데몬과 통신하며, 이 소켓에 접근하려면 <code>root</code> 권한이 있거나 <code>docker</code> 그룹에 속해 있어야 합니다.</p>
<hr>
<h3 id="sudo-없이-docker-명령어-사용하기"><strong>sudo 없이 Docker 명령어 사용하기</strong></h3>
<p>Docker 명령어를 <code>sudo</code> 없이 실행하기 위해서는 사용자를 <code>docker</code> 그룹에 추가해야 합니다. 다음 단계에 따라 설정을 진행할 수 있습니다.</p>
<h4 id="1-현재-사용자를-docker-그룹에-추가"><strong>1. 현재 사용자를 <code>docker</code> 그룹에 추가</strong></h4>
<p>먼저, 현재 사용자를 <code>docker</code> 그룹에 추가해야 합니다. 이를 통해 <code>sudo</code> 없이 Docker 명령어를 실행할 수 있습니다.</p>
<pre><code class="language-bash">sudo usermod -aG docker $USER</code></pre>
<p>위 명령어는 현재 사용자를 <code>docker</code> 그룹에 추가합니다. <code>$USER</code>는 현재 로그인한 사용자 계정을 의미합니다.</p>
<h4 id="2-그룹-변경-사항-적용"><strong>2. 그룹 변경 사항 적용</strong></h4>
<p>사용자를 <code>docker</code> 그룹에 추가한 후, 로그아웃 후 다시 로그인하여 그룹 변경 사항을 적용해야 합니다. 혹은 아래 명령어로 세션을 새로 시작할 수 있습니다.</p>
<pre><code class="language-bash">newgrp docker</code></pre>
<p>이 명령어는 로그아웃 없이도 그룹 변경 사항을 즉시 반영해줍니다.</p>
<h4 id="3-docker-명령어-실행-확인"><strong>3. Docker 명령어 실행 확인</strong></h4>
<p>이제 <code>sudo</code> 없이 Docker 명령어를 실행할 수 있는지 확인합니다.</p>
<pre><code class="language-bash">docker ps -a</code></pre>
<p>컨테이너 목록이 정상적으로 출력되면 권한 설정이 완료된 것입니다.</p>
<pre><code class="language-bash">CONTAINER ID   IMAGE         COMMAND    CREATED         STATUS                     PORTS     NAMES
0f7942c7eaf7   hello-world   &quot;/hello&quot;   3 minutes ago   Exited (0) 3 minutes ago             romantic_hopper</code></pre>
<p>위와 같이 출력되었다면, Docker 명령어가 제대로 작동하고 있는 것입니다.</p>
<h4 id="4-컨테이너-삭제-예시"><strong>4. 컨테이너 삭제 예시</strong></h4>
<p>테스트로 생성된 <code>hello-world</code> 컨테이너를 삭제해보겠습니다. 컨테이너 ID를 확인한 후 삭제 명령어를 실행합니다.</p>
<pre><code class="language-bash">docker rm 0f7942c7eaf7</code></pre>
<p>삭제가 완료되면 다시 컨테이너 목록을 확인하여, 삭제되었는지 확인합니다.</p>
<pre><code class="language-bash">docker ps -a</code></pre>
<hr>
<h3 id="docker-명령어-관련-추가-해결-방안"><strong>Docker 명령어 관련 추가 해결 방안</strong></h3>
<p>위의 설정을 완료했음에도 여전히 문제가 발생할 수 있습니다. 몇 가지 추가적인 확인 방법을 소개합니다.</p>
<h4 id="1-docker-서비스-상태-확인"><strong>1. Docker 서비스 상태 확인</strong></h4>
<p>Docker 데몬이 실행 중인지 확인합니다. 만약 Docker가 실행 중이 아니면, 서비스가 정상적으로 동작하지 않으므로 명령어 실행이 불가능합니다.</p>
<pre><code class="language-bash">sudo systemctl status docker</code></pre>
<p>Docker가 실행 중이지 않다면, 다음 명령어로 서비스를 시작할 수 있습니다.</p>
<pre><code class="language-bash">sudo systemctl start docker</code></pre>
<h4 id="2-docker-데몬-소켓-권한-확인"><strong>2. Docker 데몬 소켓 권한 확인</strong></h4>
<p>Docker 데몬과의 통신에 사용되는 소켓 파일(<code>/var/run/docker.sock</code>)의 권한이 올바르지 않을 경우, 접근 권한 문제로 인해 Docker 명령어 실행이 실패할 수 있습니다. 다음 명령어로 소켓 파일의 권한을 확인합니다.</p>
<pre><code class="language-bash">ls -l /var/run/docker.sock</code></pre>
<p>출력 결과에서 소켓 파일의 소유자와 그룹이 적절하게 설정되었는지 확인하세요. 만약 문제가 있다면 아래 명령어로 권한을 수정할 수 있습니다.</p>
<pre><code class="language-bash">sudo chown $USER /var/run/docker.sock
sudo chmod 666 /var/run/docker.sock</code></pre>
<h4 id="3-권한-변경-후-명령어-재실행"><strong>3. 권한 변경 후 명령어 재실행</strong></h4>
<p>모든 권한 설정이 완료된 후, 다시 Docker 명령어를 실행해 봅니다. 이로써 문제가 해결되었는지 확인하세요.</p>
<pre><code class="language-bash">docker ps -a</code></pre>
<hr>
<h3 id="마무리"><strong>마무리</strong></h3>
<p>이 글에서는 <code>sudo</code> 없이 Docker 명령어를 실행하기 위해 필요한 설정과 권한 문제를 해결하는 방법을 다뤘습니다. 사용자 권한을 올바르게 설정하면 <code>sudo</code> 없이도 Docker를 효율적으로 사용할 수 있으며, 시스템에 대한 불필요한 관리자 권한 사용을 줄일 수 있습니다.</p>
<p><strong>주요 요약:</strong></p>
<ol>
<li>사용자를 <code>docker</code> 그룹에 추가.</li>
<li>그룹 변경 사항 적용을 위해 로그아웃 후 다시 로그인하거나 <code>newgrp docker</code> 명령어 실행.</li>
<li>Docker 서비스 및 소켓 권한 확인.</li>
</ol>
<p>이 과정을 통해 더 편리하고 안전하게 Docker를 사용할 수 있길 바랍니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로세스에서 없는 파이프에 쓰려고 했습니다.]]></title>
            <link>https://velog.io/@nft_sb/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%97%90%EC%84%9C-%EC%97%86%EB%8A%94-%ED%8C%8C%EC%9D%B4%ED%94%84%EC%97%90-%EC%93%B0%EB%A0%A4%EA%B3%A0-%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@nft_sb/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%97%90%EC%84%9C-%EC%97%86%EB%8A%94-%ED%8C%8C%EC%9D%B4%ED%94%84%EC%97%90-%EC%93%B0%EB%A0%A4%EA%B3%A0-%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Thu, 10 Oct 2024 03:13:11 GMT</pubDate>
            <description><![CDATA[<h3 id="ssh-connection-issue-프로세스에서-없는-파이프에-쓰려고-했습니다-해결-방법"><strong>SSH Connection Issue: &quot;프로세스에서 없는 파이프에 쓰려고 했습니다&quot; 해결 방법</strong></h3>
<p>최근 SSH 연결 문제를 해결하면서 경험한 내용을 공유하고자 합니다. 이 글에서는 SSH 접속 중 발생할 수 있는 <code>프로세스에서 없는 파이프에 쓰려고 했습니다</code> 오류와 이를 해결한 과정을 다룹니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/43b7a7bd-acb8-441c-abc0-9aa77e52b51e/image.png" alt=""></p>
<h3 id="문제-발생-상황"><strong>문제 발생 상황</strong></h3>
<p>SSH를 사용하여 원격 서버에 연결을 시도할 때 다음과 같은 에러 메시지가 발생했습니다:</p>
<pre><code>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!        @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
...
프로세스에서 없는 파이프에 쓰려고 했습니다.
</code></pre><p>이 메시지는 <strong>Man-in-the-Middle 공격</strong> 또는 <strong>서버의 호스트 키 변경</strong>을 의미할 수 있으며, 보안 문제를 암시하는 경고입니다. 주된 이유는 <strong>호스트 키가 변경</strong>되었기 때문입니다. SSH 클라이언트는 호스트 키를 <code>known_hosts</code> 파일에 저장하여 서버의 신원을 확인합니다. 만약 서버의 키가 변경되면, 클라이언트는 이를 의심스러운 상황으로 간주하고 연결을 차단합니다.</p>
<hr>
<h3 id="문제-원인-분석"><strong>문제 원인 분석</strong></h3>
<p><code>Host key verification failed.</code>라는 메시지는 SSH 클라이언트가 원격 서버의 호스트 키와 <code>known_hosts</code> 파일에 저장된 키가 일치하지 않는다는 것을 의미합니다. 이는 다음과 같은 경우에 발생할 수 있습니다:</p>
<ol>
<li><strong>서버의 SSH 호스트 키가 실제로 변경된 경우</strong>: 서버를 재설치하거나, SSH 설정이 변경되었을 때.</li>
<li><strong>Man-in-the-Middle 공격 가능성</strong>: 누군가 중간에서 연결을 가로채려는 시도일 수도 있음.</li>
<li><strong>서버 IP 변경 또는 네트워크 재설정</strong>: 서버 IP가 변경된 후에도 기존 호스트 키가 남아 있는 경우.</li>
</ol>
<p>이로 인해 SSH 클라이언트는 보안 문제로 인해 연결을 차단합니다.</p>
<hr>
<h3 id="해결-방법"><strong>해결 방법</strong></h3>
<p>이 문제를 해결하기 위해서는 SSH 클라이언트의 <code>known_hosts</code> 파일에서 기존 호스트 키를 제거하고 새 호스트 키를 추가해야 합니다.</p>
<h3 id="1-문제의-호스트-키-삭제"><strong>1. 문제의 호스트 키 삭제</strong></h3>
<p>SSH는 원격 서버의 호스트 키를 <code>C:\\Users\\user\\.ssh\\known_hosts</code> 파일에 저장합니다. 이 파일에서 문제가 발생한 호스트의 키를 삭제해야 합니다.</p>
<ol>
<li><p><strong>파일 경로</strong>: <code>C:\\Users\\user\\.ssh\\known_hosts</code></p>
</li>
<li><p><strong>수정 방법</strong>:</p>
<ul>
<li><p>해당 파일을 텍스트 편집기(예: 메모장, VS Code)로 열고, 에러 메시지에 나온 줄 번호(<code>Offending ECDSA key in C:\\Users\\user/.ssh/known_hosts:6</code>)를 찾아 삭제합니다.</p>
<pre><code>C:\\Users\\user\\.ssh\\known_hosts:6
</code></pre></li>
</ul>
</li>
<li><p>해당 키를 삭제한 후 파일을 저장합니다.</p>
</li>
</ol>
<h3 id="2-ssh-재실행"><strong>2. SSH 재실행</strong></h3>
<p><code>known_hosts</code> 파일에서 기존 호스트 키를 삭제한 후, SSH 연결을 다시 시도합니다. 새로운 호스트 키를 받아들이는 메시지가 나오면 <code>yes</code>를 입력하여 신뢰를 수락합니다.</p>
<pre><code class="language-bash">ssh user@192.168.1.47
</code></pre>
<p>이제 새로운 호스트 키가 <code>known_hosts</code>에 저장되고 정상적으로 연결됩니다.</p>
<hr>
<h3 id="추가-참고-사항"><strong>추가 참고 사항</strong></h3>
<p>호스트 키가 변경된 이유가 실제로 보안 문제인지, 아니면 단순한 서버 재설치나 IP 변경인지 명확히 확인하는 것이 중요합니다. 만약 호스트 키가 변경된 이유를 모른다면, 서버 관리자에게 문의하거나 로그를 분석하여 의심스러운 활동이 없는지 확인하는 것이 좋습니다.</p>
<hr>
<h3 id="마무리"><strong>마무리</strong></h3>
<p>SSH를 사용할 때 호스트 키가 변경되는 상황은 종종 발생할 수 있습니다. 이번 포스트에서는 <code>known_hosts</code> 파일을 수정하여 이를 해결하는 방법을 소개했습니다. SSH 연결 관련 오류를 만났을 때, 차분히 문제 원인을 분석하고, 적절한 해결책을 적용하면 대부분의 문제를 해결할 수 있습니다.</p>
<p>위와 같은 방법으로 호스트 키 문제를 해결하셨다면, 다음 번에는 SSH 설정을 더욱 강화하여 안전한 원격 서버 관리를 이어가시길 바랍니다.</p>
<p><strong>문제 요약:</strong></p>
<ul>
<li><strong>오류 메시지</strong>: &quot;프로세스에서 없는 파이프에 쓰려고 했습니다.&quot;</li>
<li><strong>해결 방법</strong>: <code>C:\\Users\\user\\.ssh\\known_hosts</code> 파일에서 해당 호스트 키 삭제 후 재연결.</li>
</ul>
<hr>
<p>이 글이 SSH 관련 문제 해결에 도움이 되었기를 바랍니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ChatGPT 연동 공인중개사 웹 기획]]></title>
            <link>https://velog.io/@nft_sb/ChatGPT-%EC%97%B0%EB%8F%99-%EA%B3%B5%EC%9D%B8%EC%A4%91%EA%B0%9C%EC%82%AC-%EC%9B%B9-%EA%B8%B0%ED%9A%8D</link>
            <guid>https://velog.io/@nft_sb/ChatGPT-%EC%97%B0%EB%8F%99-%EA%B3%B5%EC%9D%B8%EC%A4%91%EA%B0%9C%EC%82%AC-%EC%9B%B9-%EA%B8%B0%ED%9A%8D</guid>
            <pubDate>Sat, 25 Mar 2023 06:44:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nft_sb/post/cd9bb448-2d17-4c66-9c6e-933ae3f9c6da/image.gif" alt=""></p>
<p>토지 공장 매매 임대를 전문으로 하는 경남 김해시 대동면의 공인중개사무소와
원룸 상가 매매 임대를 전문으로 하는 부산 강서구 신호동의 공인중개사무소의 웹사이트를 제작한다.
부동산 입지 분석과 중개 물건 소개를 컨텐츠로 하여 매수인 매도인 임대인 임차인에게 가치를 제공한다.</p>
<h2 id="웹사이트의-목적과-목표-정의">웹사이트의 목적과 목표 정의</h2>
<ul>
<li>신규 고객을 유치하거나 기존 고객에게 정보를 제공</li>
<li>중개사무소의 서비스와 전문성을 제공</li>
</ul>
<h2 id="대상-고객-식별">대상 고객 식별</h2>
<ul>
<li>중개 서비스 또는 투자 조언을 찾는 개인 또는 기업일 수 있다.</li>
</ul>
<h2 id="콘텐츠-전략-개발">콘텐츠 전략 개발</h2>
<ul>
<li>웹사이트의 콘텐츠는 대상 고객에게 유익하고 매력적이며 관련성이 있어야 한다.</li>
<li>블로그 게시물, 시장 분석 또는 투자 조언과 같이 게시할 콘텐츠 유형을 포함하는 콘텐츠 전략을 개발한다.</li>
</ul>
<h2 id="웹사이트-디자인">웹사이트 디자인</h2>
<ol>
<li>CI/BI 및 웹페이지 레이아웃 아이디어는 생성형 AI를 이용하여 발전.</li>
</ol>
<ul>
<li>웹사이트 디자인은 중개사무소의 브랜드와 가치를 반영하여 전문적이고 시각적으로 매력적이어야 한다.</li>
<li>사용자 경험을 향상시키기 위해 이미지, 비디오 및 기타 미디어를 사용하는 것을 고려해본다.</li>
</ul>
<h2 id="웹사이트-구축">웹사이트 구축</h2>
<ol>
<li>AICodeHelper 익스텐션을 이용한 코딩 과정 간소화<ol>
<li><a href="https://www.youtube.com/watch?v=Uc7md60uAKM">참고자료</a></li>
</ol>
</li>
</ol>
<h3 id="요구기능">요구기능</h3>
<ol>
<li>사무소의 매물 대장 엑셀을 chatGPT를 연동하여 중개가 완료된 매물의 상세 정보 토지 및 입지 분석을 통한 게시글 업로드 자동화.</li>
<li>사무소의 매물 대장 엑셀을 chatGPT를 연동하여 중개 진행 중인 매물의 제한된 정보 토지 및 입지 분석을 통한 게시글 업로드 자동화.</li>
<li>관리자와의 실시간 채팅 상담 기능</li>
<li>상세기능<ol>
<li>반응형 웹으로 TV, Web, Tablet, Mobile을 고려하여 개발한다.</li>
<li>상태관리<ol>
<li>로그인 로그아웃<ol>
<li>관리자 로그인</li>
<li>사용자 로그인</li>
<li>비회원 </li>
</ol>
</li>
</ol>
</li>
</ol>
</li>
</ol>
<ul>
<li><h2 id="연락처-양식-온라인-계정-액세스-및-소셜-미디어-통합과-같은-기능을-포함한다">연락처 양식, 온라인 계정 액세스 및 소셜 미디어 통합과 같은 기능을 포함한다.</h2>
</li>
</ul>
<h2 id="웹사이트-테스트-및-시작">웹사이트 테스트 및 시작</h2>
<ul>
<li>사용성, 기능 및 다양한 장치 및 브라우저와의 호환성에 대해 웹사이트를 철저하게 테스트한다.</li>
<li>모든 것이 올바르게 작동하면 웹사이트를 시작하고 이메일 마케팅, 소셜 미디어 및 기타 채널을 통해 홍보하자.</li>
</ul>
<h2 id="웹사이트-유지-및-업데이트">웹사이트 유지 및 업데이트</h2>
<ul>
<li>새로운 콘텐츠, 시장 분석 및 투자 조언으로 웹사이트를 정기적으로 업데이트한다. 웹 사이트의 성능과 사용자 참여를 모니터링하고 필요에 따라 개선한다.</li>
</ul>
<h2 id="마무리">마무리</h2>
<p>전반적으로 공인중개사무소를 위한 웹 사이트를 개발하려면 신중한 계획, 사용자 경험에 대한 집중, 지속적인 유지 관리 및 업데이트에 대한 노력이 필요하다. 고객에게 가치를 제공하고 비즈니스 목표를 달성하는 데 도움이 되는 웹사이트를 만들어 보자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SCSS (Sassy CSS)]]></title>
            <link>https://velog.io/@nft_sb/SCSS-Sassy-CSS</link>
            <guid>https://velog.io/@nft_sb/SCSS-Sassy-CSS</guid>
            <pubDate>Mon, 20 Feb 2023 12:49:36 GMT</pubDate>
            <description><![CDATA[<p>SCSS (Sassy CSS) is a preprocessor that extends the capabilities of CSS, making it more powerful and flexible. It provides a variety of features, such as variables, functions, and mixins, that can help make your stylesheets easier to read and maintain. In this article, we&#39;ll take a look at how to use SCSS to create more efficient and maintainable CSS.</p>
<p>Installing SCSS
Before we can start using SCSS, we need to install it. The easiest way to do this is to use a package manager, such as npm or yarn. We can install SCSS using npm by running the following command:</p>
<pre><code class="language-scss">npm install sass</code></pre>
<p>Basic Syntax
SCSS is a superset of CSS, which means that all valid CSS is also valid SCSS. SCSS files are saved with a .scss file extension, and they are compiled into CSS files that can be used in your web pages.</p>
<p>Here is an example of basic SCSS syntax:</p>
<pre><code class="language-scss">// Define a variable
$primary-color: #f00;

// Use the variable in a style rule
body {
  background-color: $primary-color;
}</code></pre>
<p>When this SCSS code is compiled, it will produce the following CSS:</p>
<pre><code class="language-scss">body {
  background-color: #f00;
}</code></pre>
<p>Variables
Variables are a powerful feature of SCSS that allow you to define reusable values. Variables in SCSS are denoted by the $ symbol. Here is an example:</p>
<pre><code class="language-scss">$primary-color: #f00;

body {
  background-color: $primary-color;
}</code></pre>
<p>This will produce the following CSS:</p>
<pre><code class="language-scss">body {
  background-color: #f00;
}</code></pre>
<p>Variables can be used to define a wide range of values, such as font sizes, border widths, and colors.</p>
<p>Nesting
SCSS allows you to nest style rules, making it easier to organize your code and make it more readable. Here is an example:</p>
<pre><code class="language-scss">nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;

    li {
      display: inline-block;
      margin: 0 10px;
    }
  }
}</code></pre>
<p>This will produce the following CSS:</p>
<pre><code class="language-scss">nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

nav ul li {
  display: inline-block;
  margin: 0 10px;
}</code></pre>
<p>Mixins
Mixins are a way to define reusable blocks of code. They are similar to functions in other programming languages. Here is an example:</p>
<pre><code class="language-scss">@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
  border-radius: $radius;
}

button {
  @include border-radius(5px);
}
This will produce the following CSS:

css
Copy code
button {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
}</code></pre>
<p>Functions
SCSS also provides a number of built-in functions that can be used to manipulate values. Here are a few examples:</p>
<pre><code class="language-scss">$width: 100px;

// Returns the value with a unit of em
width: em($width);

// Returns the value with a unit of rem
width: rem($width);

// Returns a color that is 50% lighter than the input color
color: lighten(#f00, 50%);</code></pre>
<p>Importing
SCSS allows you to split your code into separate files and then import them into a main file. This makes</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] 데이터 바인딩 이해하기(단방향, 양방향 데이터 바인딩)]]></title>
            <link>https://velog.io/@nft_sb/JS-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0%EB%8B%A8%EB%B0%A9%ED%96%A5-%EC%96%91%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9</link>
            <guid>https://velog.io/@nft_sb/JS-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0%EB%8B%A8%EB%B0%A9%ED%96%A5-%EC%96%91%EB%B0%A9%ED%96%A5-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B0%94%EC%9D%B8%EB%94%A9</guid>
            <pubDate>Fri, 17 Feb 2023 04:30:34 GMT</pubDate>
            <description><![CDATA[<h2 id="1-데이터-바인딩data-binding이란">1) 데이터 바인딩(Data Binding)이란?</h2>
<p>💡 화면상에 보여지는 데이터(View)와 브라우저 메모리에 있는 데이터(Model)를 묶어서(Binding) 서로 간의 데이터를 동기화하는 것을 의미합니다.</p>
<p>💡 예를 들어서 HTML에서 서버 혹은 스크립트상에서 받아온 데이터를 화면상에 그려주고 있다고 가정을 했을 때, 해당 값이 변경이 될 경우 다시 HTML 상에 데이터(값)를 변경된 값에 따라서 맞추어 주는 동작을 &#39;데이터 바인딩&#39;이라고 합니다.</p>
<h3 id="-간단한-예제---1--값을-데이터-바인딩한다">[ 간단한 예제 - 1 ] 값을 데이터 바인딩한다.</h3>
<p>💡 아래의 예제는 함수형 컴포넌트 안에서 ‘initData’로 초기화 한 값을 최초 HTML상에 출력합니다. 이후 ‘재 데이터 바인딩’ 버튼을 누르면 상태 값을 변경시키고, HTML에서 데이터 바인딩을 하는 예시입니다.
import React, { useState } from &#39;react&#39;;
import { CommonType } from &#39;../../type/common/CommonType&#39;;</p>
<pre><code class="language-javascript">const DataBindingBasicComponent = () =&gt; {

    /**
     * 브라우져 메모리상에 존재하는 데이터 
     */
    const [initData, setInitData] = useState({
        greet: &quot;안녕하세요&quot;,
        info: &quot;데이터 바인딩에 대해서 공부하고 있습니다.&quot;
    });

    /**
     * 버튼을 클릭하면 상태로 지정한 메모리로 데이터를 바인딩 한다.
     */
    const reDataBinding = () =&gt; {
        setInitData({
            greet: &quot;다시 한번 반갑습니다&quot;,
            info: &quot;데이터를 바인딩 합니당&quot;
        })
    };
    return (
        &lt;div&gt;
            &lt;h1&gt;{initData.greet}&lt;/h1&gt;
            &lt;h2&gt;{initData.info}&lt;/h2&gt;
            &lt;button onClick={reDataBinding}&gt;재 데이터 바인딩&lt;/button&gt;
        &lt;/div&gt;
    );
}

export default DataBindingBasicComponent;

</code></pre>
<h3 id="-간단한-예제---2--css-값스타일을-데이터-바인딩한다">[ 간단한 예제 - 2 ] CSS 값(스타일)을 데이터 바인딩한다.</h3>
<p>💡 아래의 예제는 함수형 컴포넌트 안에서 ‘initCSSStyle’로 초기화 한 ‘스타일’을 최초 HTML상에 출력합니다. 이후 ‘재 데이터 바인딩’ 버튼을 누르면 상태 값을 변경시키고, HTML에서 데이터 바인딩을 하는 예시입니다.</p>
<pre><code class="language-javascript">import React, { useState } from &#39;react&#39;;
const DataBindingCSSComponent = () =&gt; {

    /**
     * 브라우져 메모리상에 존재하는 데이터(CSS Style) 
     */
    const [initCSSStyle, setInitCSSStyle] = useState({
        color: &quot;red&quot;,
        fontSize: &quot;30&quot;
    });

    /**
     * 버튼을 클릭하면 상태로 지정한 메모리로 데이터를 바인딩 한다.
     */
    const reDataBinding = () =&gt; {
        setInitCSSStyle({
            color: &quot;yellow&quot;,
            fontSize: &quot;50&quot;
        });
    };
    return (
        &lt;div&gt;
            &lt;h1 style={initCSSStyle}&gt;안녕하세요&lt;/h1&gt;
            &lt;h2 style={initCSSStyle}&gt;만나서 반갑습니다.&lt;/h2&gt;
            &lt;button onClick={reDataBinding}&gt;재 데이터 바인딩&lt;/button&gt;
        &lt;/div&gt;
    )
}

export default DataBindingCSSComponent;</code></pre>
<h2 id="2-단방향-데이터-바인딩one-way-data-binding이란">2) 단방향 데이터 바인딩(One-way Data Binding)이란?</h2>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/7c5e3cc7-6e55-4529-9d11-6def54d3f8e5/image.png" alt=""></p>
<p>💡 컴포넌트 내에서 &#39;단방향 데이터 바인딩&#39;은 Javascript(Model)에서 HTML(View)로 한 방향으로만 데이터를 동기화하는 것을 의미합니다. [JS(Model) -&gt; HTML(View)]</p>
<p>💡 단방향 데이터 바인딩이기에 역으로 HTML(View)에서 JS(Model)로의 직접적인 데이터 갱신은 불가능합니다. &#39;이벤트 함수(onClick, onChange,...)&#39;를 주고 함수를 호출한 뒤 Javascript에서 HTML로 데이터를 변경해야 합니다. [HTML(View) -&gt; JS(Model)]</p>
<p>💡 컴포넌트 간에서 단방향 데이터 바인딩은 부모 컴포넌트에서 자식 컴포넌트로만 데이터가 전달되는 구조입니다.</p>
<p>💡 대표적으로 SPA Framework에서는 React에서 단방향 데이터 바인딩을 합니다.</p>
<h2 id="3-양방향-데이터-바인딩two-way-data-binding이란">3) 양방향 데이터 바인딩(Two-way Data Binding)이란?</h2>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/981b6e71-c53a-4669-b77d-b1f9b3f9fef0/image.png" alt=""></p>
<p>💡 컴포넌트 내에서 &#39;양방향 데이터 바인딩&#39;은 Javascript(Model)와 HTML(View) 사이에 ViewModel이 존재하여 하나로 묶여서(Binding) 되어서 둘 중 하나만 변경되어도 함께 변경되는 것을 의미합니다. [HTML(View) &lt;-&gt; ViewModel &lt;-&gt; Javascript(Model)]</p>
<p>💡 컴포넌트 간에서는 부모 컴포넌트에서 자식 컴포넌트로는 Props를 통해 데이터를 전달하고, 자식 컴포넌트에서 부모 컴포넌트로는 Emit Event를 통해서 데이터를 전달하는 구조입니다.</p>
<p>💡 대표적으로 SPA Framework에서는 Vue.js, Angular에서 양방향 데이터 바인딩을 합니다.</p>
<p>출처:<a href="https://adjh54.tistory.com/49">https://adjh54.tistory.com/49</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Project Entasis]]></title>
            <link>https://velog.io/@nft_sb/Project-Entasis</link>
            <guid>https://velog.io/@nft_sb/Project-Entasis</guid>
            <pubDate>Thu, 16 Feb 2023 14:05:17 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nft_sb/post/02b3aafc-7737-4ad7-a4b5-15b1e93155ef/image.gif" alt=""></p>
<p>팀 소개
팀명 : ENTASIS
프로젝트 명 : STO 튜토리얼
팀원 : 윤수빈(팀장), 김현태, 박도형, 백준석
시연 영상 : <a href="https://www.youtube.com/watch?v=0fmODCTVs0g">https://www.youtube.com/watch?v=0fmODCTVs0g</a>
Github 링크 : GitHub - codestates-beb/BEB-07-final-entasis
배포 링크 : React App
블록체인 네트워크 주소 : <a href="http://18.183.252.200:8545">http://18.183.252.200:8545</a> 체인ID : 1337
2. 프로젝트 소개
[ STO 거래소 튜토리얼 “ENTASIS” ]
“당신은 STO에 대해 알고 계십니까?”
이 질문을 받는 대부분의 사람들은 잘 모른다고 답할 것입니다. 주식, 채권, 코인 등에 투자를 한 경험은 많지만, 대다수의 사람들이 STO에 대해서는 모르는 만큼, 투자자의 입장에서 STO가 무엇이고, 어떤 기능이 있으며, 어떻게 투자할 수 있는지를 이 프로젝트를 통해 이해하도록 도움으로써 증권형 토큰에 대한 투자를 확대시키는 것이 이 프로젝트의 목표입니다.</p>
<p>글로벌 자산운용사 블랙록의 대표 래리핑크는 2022. 12. 1. 인터뷰에서 STO를 통해 현재 증권 거래 비용에 포함된 브로커들의 수수료를 매매 당사자들에게 나누어주며 수수료가 낮아질 것이고 투표 또한 ST 소유자들이 할 수 있게 될 것이라고 말했습니다. 이 블랙록 자산운용사 대표의 STO에 대한 인식은 프로젝트 주제 선정에 결정에 도움을 주었습니다.</p>
<p>우리가 흔히 알고 있는 토큰은 ICO를 기반한 ‘유틸리티 토큰’ 입니다.</p>
<p>그렇다면 STO란 무엇일까요?
<img src="https://velog.velcdn.com/images/nft_sb/post/42914413-9ec9-497b-98c9-7d3b6e63cc2b/image.png" alt=""></p>
<p>우선 STO의 기반이 되는 “증권형 토큰(Secturity Token)”이 무엇인지에 대해 이해할 필요가 있습니다.</p>
<p>증권형 토큰(일명 ST)은 기업이 주식, 채권 대신 암호화폐 형태로 발행하는 유가 증권입니다. 이 증권형 토큰은 블록체인 플랫폼이 제공하는 서비스를 활용할 권리 대신 주식과 마찬가지로 기업의 법적 소유권을 가졌음을 의미합니다. 때문에 증권형 토큰을 보유하고 있으면 기업 또는 기업의 블록체인 플랫폼이 낸 수익이나 자산의 일부를 배당받을 수 있습니다.</p>
<p>증권형 토큰은 그 용도가 주식, 채권 등 유가증권과 동일하기 때문에 법과 정책의 개입과 규제를 받아야만 합니다. 상법에 정해진 절차에 따라 주식을 발행하듯 관련 법에 따라 증권형 토큰을 발행해야 한다는 것입니다.</p>
<p>이 증권형 토큰을 IPO와 같이 상장하여 거래가 이루어지도록 하는 것이 STO 입니다.</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/ef3ca603-5c3f-4f86-b858-6421da959b8c/image.gif" alt=""></p>
<p>[ About Service ]
Entasis는 실제 STO 거래소의 기능을 일부 축소하여 상대적으로 기업보다 STO에 대해 접근을 어려워 할 개인 투자자들에게 실제 ST에 투자를 해봄으로써 증권형 토큰에 대해서 더 쉽게 이해하고 접근할 수 있도록 도와주는 “STO 거래소 튜토리얼” 입니다.</p>
<p>기본 환경 조성
토큰 가격 형성 및 변동성
실제 거래소에서 Market Maker &amp; Market Taker 와 토큰 매매를 통해 가격이 형성이 되지만, 이 프로젝트를 진행하는데 있어서 튜토리얼이라는 점과 대규모의 트래픽이 기대되지 않는다는 점으로 인해 실제 거래소에서 가격 형성이 되는 방식으로 구현하는 것은 제한된다고 판단하였습니다.
그에 따라 난수를 통해 가격을 형성하고 주기적으로 가격이 변동할 수 있도록 구현하였습니다.
단기 변동성과 중장기 변동성, 기업의 당기순이익 발표의 값이 난수로 설정되어 각각 3 개의 ST시장을 형성했습니다. 또한 당기순이익에 배당률을 적용하여 기업의 이익을 지분에 따라 배당합니다. 토큰 소유자는 지분율에 따라 투표를 할 수 있습니다.
블록체인
이더리움 : EC2 인스턴스에서 백그라운드로 가나슈 네트워크를 실행시켰으며, 트러플을 이용하여 컨트랙트를 배포하였습니다.
근본적으로 토큰 거래 기능을 위해 ERC20을 사용하였으며, 증권형 토큰의 기능 일부를 추가하기 위해 ERC1400의 운영자 및 제어자 변수와 거래제한 함수를 발췌하였습니다.
투자자 입장에서 다양한 토큰에 대해서 분석하고 거래를 할 필요가 있다고 판단하여 3개의 기업으로 다양화하여 3개의 컨트랙트를 배포하였으며, 토큰 거래가 이루어질 때마다 해당 토큰 보유자 배열에 저장하여 배당금을 분배할 때 토큰 보유 여부를 확인할 수 있도록 하였습니다.
스테이킹시 토큰 매매 제한을 강제하기 위해서 스테이킹의 모든 기능은 컨트랙트 내에서 구현하였으며, 만료일을 계산하는 데에는 block.timestamp 를 이용하여 만료 여부를 확인할 수 있도록 하였습니다.</p>
<p>주요 기능
실시간으로 가격 변동이 일어나는 차트 중심의 한 메인 페이지</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/f8f5ab05-e25f-499d-a3ef-afd873e0f0af/image.png" alt=""></p>
<p>메타 마스크를 통한 지갑 등록</p>
<p>회원가입을 따로 진행할 필요가 없으며, 메타마스크로 지갑등록을 하면 자동으로 로그인이 됩니다.
메타마스크가 설치되어있지 않은 경우 메타마스크 설치 링크로 유도합니다.
처음 로그인을 하는 메타마스크 지갑인 경우 DB에 등록을 합니다.
튜토리얼 및 이용법 설명
<img src="https://velog.velcdn.com/images/nft_sb/post/65b2e5ac-caed-41ff-9c74-7dabb7f4f641/image.gif" alt=""></p>
<p>FAUCET (초기 자본금)
튜토리얼을 완료하면 자동으로 faucet 기능을 통해 50ETH가 부여됩니다.
faucet은 1회만 받을 수 있습니다.
ETH를 통한 증권형 토큰 구매 및 판매</p>
<p>실시간으로 변하는 가격을 보고 토큰을 구매 및 판매할 수 있습니다.
투자자가 토큰 거래를 할 경우 메타마스크를 통해 서명이 됩니다.
거래 수수료는 거래대금의 0.04%로 자동으로 계산이 됩니다.
배당금 투표
<img src="https://velog.velcdn.com/images/nft_sb/post/51788ab0-f6d0-45e7-a767-4e98e34d619d/image.gif" alt=""></p>
<p>10분에 한 번씩 지급되는 배당금에 대한 배당률을 결정하기 위해 배당률 투표가 이루어집니다.
투표를 하지 않더라도 배당금을 받을 수 있습니다.
배당금 지급
<img src="https://velog.velcdn.com/images/nft_sb/post/755f312f-188e-4754-8e4b-58609508afd0/image.gif" alt=""></p>
<p>토큰 별로 totalSupply 대비 투자자가 보유하고 있는 토큰양에 따라 배당금이 지불됩니다.</p>
<p>거래제한(Circuit Breaker)
극단적인 가격 변동률이 발생할 경우 모든 토큰에 거래를 제한시켜 버리는 기능입니다.
1분간 거래가 불가능해지며 이에 따라 토큰 가격도 1분간 변동하지 않습니다.
우리 프로젝트에서는 극단적인 가격 변동이 일어날 일이 없는 점으로 인해 거래 제한 기능을 보여주기 위하여 Circuit Breaker 버튼을 누를 경우 거래 제한이 발동하도록 구현하였습니다.
[거래 제한 발동]</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/a672df70-a92d-4f77-9a25-0079e91743cc/image.gif" alt=""></p>
<p>[거래 제한 해제]</p>
<p><img src="blob:https://velog.io/92060809-5e08-4bf0-9c6b-56501601bc6c" alt="업로드중.."></p>
<p>스테이킹 기능(Staking)
스테이킹은 본인이 보유하고 있는 디지털자산을 블록체인 네트워크에 맡기는 방식으로 현금을 은행에 맡기는 예금과 구조가 비슷합니다. 또 보유한 디지털 자산을 블록체인 검증에 활용하도록 맡기는 것을 뜻합니다.
스테이킹을 할 경우 일정기간동안 토큰을 거래소에 맡기고 기간이 만료되면 상대적으로 높은 이율에 따른 보상과 함께 토큰을 돌려받게 됩니다.
단, 스테이킹 기간동안에는 해당 토큰을 사용할 수 없기 때문에, 토큰 가격이 변동으로 인해 토큰을 돌려 받고 싶어도 해당 기간동안에는 돌려 받을 수 없습니다.</p>
<p>[스테이킹 요청시]
사용자는 Staking 버튼을 눌러 메타마스크를 통해 서명한 데이터를 원하는 ST 컨트랙트에 보내 스테이킹을 진행합니다.
이 때, 이미 스테이킹이 되어있거나 기입한 Amount(수량)보다 토큰 보유량이 적을 시 에러가 반환됩니다.
토큰이 문제없이 스테이킹이 된다면 우측 Amount List와 Reward List가 갱신되고 하단 Reward Time에 보상 인출까지 남은 기간이 표시됩니다.
[보상 인출시]
Reward Time이 Able로 변경되어 보상 인출이 가능해지면, 사용자는 Reward 버튼을 눌러 보상 인출 함수를 실행하는 데이터를 메타마스크로 서명해 컨트랙트에 보내게 됩니다.
컨트랙트에서 만료일을 확인한 후, 문제가 없다면 사용자에게 스테이킹한 Amount에 Reward를 합한 토큰을 사용자에게 전송합니다.
만료일이 지나지 않았을 경우 Reward 버튼이 비활성화 됩니다.
토큰과 보상이 사용자에게 전송되면 다시 Amount List와 Reward List가 0으로 초기화됩니다.
아키텍쳐
<img src="blob:https://velog.io/5623ceae-a401-4979-92ad-52ab0e031157" alt="업로드중.."></p>
<p>아키텍처의 경우 S3를 이용한 정적 호스트 페이지와 EC2를 이용한 서비스 서버, Database 클라우드 서버, 그리고 블록체인 네트워크 서버로 구성되어 있습니다.</p>
<p>먼저 배포과정에서는 Github Actions 를 활용하여 CI/CD 파이프라인을 구성하여 Github에서 push가 발생할 때마다 배포중인 서비스에 반영되어 자동 배포가 실행됩니다.
클라이언트는 AWS IAM를 통해 S3에 접근하여 배포하였으며, 블록체인 네트워크의 경우 AWS EC2의 인스턴스 내에서 가나슈 네트워크를 백그라운드로 실행하여 네트워크가 지속 가능하도록 설정하였습니다.
서버 부분은 EC2를 이용하여 Docker와 Github Container Registry를 사용하여 EC2내에서 백그라운드로 자동서비스를 실행할 수 있도록 설계하였습니다.
윤수빈
역할</p>
<ul>
<li>포지션 : PM / Frontend / Design</li>
<li>개인 깃허브 : <a href="https://github.com/Russ481-k">https://github.com/Russ481-k</a></li>
<li>개인 블로그 : <a href="https://www.notion.so/1-Entasis-3-b3370daa41fc463fb32d1dccac16d46e">https://www.notion.so/1-Entasis-3-b3370daa41fc463fb32d1dccac16d46e</a></li>
<li>활용 스택 : Figma / Javascript / React/ HTML / CSS / MySQL / Sequelize / Node.js / Scale-Liner / Axios</li>
<li>구현 기능 :</li>
<li>프로젝트 기획&amp;관리</li>
<li>디자인 구상 및 구현</li>
<li>프론트엔드 UI, UX 구현</li>
<li>차트 구현</li>
<li>서버 제공 API를 통한 데이터 요청</li>
<li>서버 실시간 데이터 생성 기능 구현</li>
</ul>
<p>프로젝트를 마치며
웹소켓을 적용하지 못하여 대규모 트래픽에 대비하지 못했던 것이 아쉽다. 추후에 리팩토링 과정을 통해서 해당 내용을 적용해 보고자 한다.</p>
<p>서버의 차트데이터 로직 구현 외 백엔드와 컨트랙트 부분에 역할을 맡지 못한 점에 추후 솔로 프로젝트로 해당 내용을 구현해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Project EWE ]]></title>
            <link>https://velog.io/@nft_sb/hdt6cv41</link>
            <guid>https://velog.io/@nft_sb/hdt6cv41</guid>
            <pubDate>Fri, 13 Jan 2023 15:54:53 GMT</pubDate>
            <description><![CDATA[<p>MainPage
<img src="https://velog.velcdn.com/images/nft_sb/post/d4f9118d-39fa-45d3-8987-b0f9b838f610/image.gif" alt=""></p>
<p>Responsible Web</p>
<p>Pagination with Searchbar</p>
<p>Login
<img src="https://velog.velcdn.com/images/nft_sb/post/92b1353c-cb40-47bb-9638-ba305c4acedd/image.gif" alt=""></p>
<p>MyPage
<img src="https://velog.velcdn.com/images/nft_sb/post/16a7aaa6-f2ab-4ff4-b926-769e35f5ceb1/image.gif" alt=""></p>
<p>Donate in Sidebar
<img src="https://velog.velcdn.com/images/nft_sb/post/73a50db1-66ee-4241-87e9-c5b559d85d10/image.gif" alt=""></p>
<p>NFTmint &amp; NFTdetail</p>
<p>Post</p>
<p>Asset Check
<img src="https://velog.velcdn.com/images/nft_sb/post/1b90ff13-d4fc-4633-aa2c-b51741b6887e/image.gif" alt=""></p>
<p>Signup &amp; Login &amp; Logout</p>
<p><img src="blob:https://velog.io/dd834475-aa0f-4a29-a8d4-7dd8ab955334" alt="업로드중.."></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Project EWE]]></title>
            <link>https://velog.io/@nft_sb/Project-EWE</link>
            <guid>https://velog.io/@nft_sb/Project-EWE</guid>
            <pubDate>Fri, 13 Jan 2023 06:34:32 GMT</pubDate>
            <description><![CDATA[<h1 id="team-ewe-presentation">Team EWE Presentation</h1>
<h3 id=""></h3>
<h3 id="🚦-ewe-관련-간단-개념-설명">🚦 EWE 관련 간단 개념 설명</h3>
<p>E <strong>→ Eat</strong></p>
<p>W<strong>→ Write</strong></p>
<p>E <strong>→ Earn</strong></p>
<p>기억에 남을만한 식사를 공유하고 공감하여 가치를 창출하는 인센티브 커뮤니티입니다.</p>
<h3 id="기획">기획</h3>
<ul>
<li>사용자는 맛집의 위치와 사진, 글을 포스팅하며 정보를 나눕니다.</li>
<li>포스팅을 할 경우 일정 가치의 EWE 토큰을 받습니다.</li>
<li>토큰으로 특정인에게 좋아요등의 공감을 표현할 수 있고 특정인을 후원하거나 맛집 할인 쿠폰으로 이용되는 NFT를 구매할 수 있습니다.</li>
<li>요식업체는 자사의 상품을 NFT로 소개함으로, 소비자들에게 혜택을 제공는 마케팅에 활용할 수 있습니다.</li>
<li>토큰의 가치를 관리하기 위해서 댓글과 리뷰의 가치를 측정하는 수단으로, 전문 리뷰어들의 리뷰의 글, 사진, 영상 리뷰 별 수익을 조사하여 포스트 당 리워드를 책정합니다.</li>
<li>NFT의 가치는 평균 외식 식사 비용과 요식업체 평균 할인 비율을 가중하여 구하며, 이외에 혜택을 제공하는 업체별로 할인 금액을 정할 수 있도록 합니다.</li>
<li>모든 거래는 ETH와 EWE 토큰으로 거래됩니다.</li>
</ul>
<p><strong>Design Concept  :</strong>  흰 접시 위에 올려진 정갈한 요리와 식욕을 자극시키는 과일의 상큼함</p>
<p><a href="https://www.figma.com/file/Rus9pjbRn9JIoZKwH7atDB/Project_2-%3A-Incentive-Community?t=ef9Eg4AbWKfq5j9O-0">Design from Figma</a></p>
<h3 id="requirement">Requirement</h3>
<table>
<thead>
<tr>
<th>유저인증</th>
<th>서비스가 기능을 제공하기 위하여 사용자의 인증을 검증하고 권한을 부여합니다.</th>
</tr>
</thead>
<tbody><tr>
<td>유저 지갑관리</td>
<td>토큰과 NFT 거래에 필요한 계정을 서버에서 관리합니다.</td>
</tr>
<tr>
<td>맛집 리뷰 CRUD</td>
<td>리뷰가 작성 및 수정 되는 UI가 제공되고, 데이터베이스 상에서 관리할 수 있는 데이터로 남깁니다.</td>
</tr>
<tr>
<td>리뷰 팁(토큰) 전송</td>
<td>작성된 리뷰에 토큰을 전송하여 작성자에게 보낼 수 있습니다.</td>
</tr>
<tr>
<td>쿠폰 NFT 민팅</td>
<td>NFT를 구매할 수 있습니다.</td>
</tr>
</tbody></table>
<ul>
<li>React</li>
</ul>
<p>현재 저희 구성대로라면 메인페이지, 마이페이지, 마켓페이지 모두 불러오는 데이터가 다릅니다. 고민을 하다가 어플리케이션 최상위 컴포넌트에서 데이터를 내려주기보다 각각의 페이지마다 데이터를 상태값으로 관리를 하면서 props를 통한 데이터 이동을 없애주기로 했습니다. 각각의 페이지에 존재하는 페이지네이션 컴포넌트가 새로운 데이터를 요청하고 받아오는 역할을 하는 데이터허브 역할을 합니다.</p>
<p>Pagination Diagram</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/42a68496-1c5c-4b71-913d-4a6e444bfca7/image.png" alt=""></p>
<ul>
<li>Redux</li>
</ul>
<p>유저 인증에 관한 클라이언트의 상태관리를 용이하게 하기 위하여 React Redux를 도입하였습니다. 해서 원래는 React Hooks를 이용한 리액트 내 상태값을, 리액트 앱 외부에서 전역적으로 관리를 해줬습니다. 그리고 해당 전역 상태값을 필요한 컴포넌트에서 최신의 상태값으로 제공하고, 갱신할 수 있게 구현해주었습니다. 이 덕분에 props를 통하여 컴포넌트간의 데이터 이동을 관리 하지 않고 React Hooks 처럼 필요한 데이터를 불러와 사용할 수 있어 어플리케이션의 복잡성을 낮추고, 개발 편의성을 높여줬습니다.</p>
<p>Architecture Diagram</p>
<p><a href="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/cec141d0-1f07-46a2-944b-f1fa2c604368/Untitled.png"></a></p>
<p>Server</p>
<p><a href="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ff9865fb-7398-4996-8001-50f868a03c80/Untitled.png"></a></p>
<hr>
<p><strong>Server의 역할</strong> </p>
<ol>
<li><p>User
유저정보를 관리하는 컨트롤러로 회원가입, 로그인, 로그아웃, 유저 정보 제공의 기능을
제공합니다.</p>
</li>
<li><p>Post
게시물을 관리하는 컨트롤러로 게시물 작성, 조회, 수정, 삭제의 CRUD 기능과 게시물 검색시
필터된 데이터를 반환하는 기능을 제공합니다.</p>
</li>
<li><p>NFT
NFT를 관리하는 컨트롤러로 NFT 조회, 민팅하는 기능을 제공합니다.</p>
</li>
</ol>
<p><strong>로그인 처리방법</strong></p>
<p>2가지의 로그인 방법이 존재합니다.</p>
<ol>
<li><p>로컬 로그인</p>
</li>
<li><p>네이버 로그인</p>
</li>
</ol>
<p><strong>이미지 처리 방법</strong></p>
<p>AWS S3
multer-s3</p>
<p><strong>Tech Stack</strong></p>
<p><a href="https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e0b680f6-9619-410e-81e4-7bfd0acd7bae/Untitled.png"></a></p>
<p>배포주소</p>
<p><a href="https://d3t5y0jgzx6lw2.cloudfront.net/">https://d3t5y0jgzx6lw2.cloudfront.net/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenSea  Clone Coding]]></title>
            <link>https://velog.io/@nft_sb/OpenSea-Clone-Coding</link>
            <guid>https://velog.io/@nft_sb/OpenSea-Clone-Coding</guid>
            <pubDate>Fri, 30 Dec 2022 04:49:52 GMT</pubDate>
            <description><![CDATA[<h1 id="codestates-beb-project1">Codestates BEB Project1</h1>
<p><a href="https://github.com/codestates-beb/BEB-07-first-02">OpenSea GitHub repo</a></p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/20dfa7bf-098a-47e5-b6b5-6a02217a421a/image.gif" alt=""></p>
<p>OpenSea  Clone Coding 은 4F 방식으로 기록하고자 한다.</p>
<p>사실(Fact) : 프로젝트를 통해 어떤 내용을 고민했고 어떤 방법으로 개념을 이해하고 문제를 해결했는지 작성
감정(Feeling) : 프로젝트를 진행하면서 느꼈던 감정을 솔직하게 기록
발견(Finding) : 문제를 해결하면서 무엇을 깨달았고, 시도해본 해결 방법에 대해서 개선이 필요한 부분을 발견했다면 발견 항목에 기록
다음주를 위한 행동(Future Action) : 위의 회고를 통해서 당장 다음 프로젝트에 적용해 볼 학습 방법이나 조금 더 고민이 필요한 내용, 커뮤니케이션 방식 등을 기록</p>
<h2 id="fact">Fact</h2>
<p>프론트앤드와 디자인을 맡았다.
주로 React, Html, CSS로 작업했고,
GitHub, Node.js, npm, mysql를 빌드업 할 때 사용했다.
먼저 데이터 흐름과 페이지 구성을 파악하기 위해 흐름도를 구성했다
<img src="https://velog.velcdn.com/images/nft_sb/post/386bd2d6-9913-4f0d-92e2-30f41233a475/image.PNG" alt="">
지갑을 연결한 상태에서 트랜젝션을 통해 NFT가 매매되는 것이 포인트라 생각했다.
NFT가 매매 되는 것은 NFTDetails 페이지에서 가능하다</p>
<p>가장 먼저 부딪친 부분은 깃허브였다.
git add &lt;&gt;
git commit -m &#39;&#39;
git pull pair main
git push origin main</p>
<p>충돌을 겪고 해결 방법을 찾는데에서 하루 반나절을 보냈다.
함께 프로젝트 진행하는 팀장과 팀원들의 도움으로 해결했고, 추후 프로젝트가 끝나고 구글링을 통해서 깃허브 동작방식과 깃허브 데스크탑과 Vscode 깃허브 익스텐션들을 사용하여 남은 기간동안은 깃허브로 고생하지 않게 되었다.</p>
<p>디자인
사실 팀원 분들에게는 얼마 전에 만들어 놓은 OpenSea라 했지만,
이것은 코드스테이츠 수강 직전에 만들어 놓은 버전이었다.
리액트와 백엔드에 좀 더 집중하고자 좀 더 빠른 길을 택했지만 
그 결과는 재앙을 불러오고 말았다.</p>
<p>React에서는 component 개념과 react-router-dom을 통한 페이지 구성을 했다.</p>
<p>컴포넌트와 맵핑을 통해 NFT를 리스팅 했다. 
    component
    map</p>
<p>Axios는 브라우저, Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리이다.
axios와 url을 통해 서버와 통신하는 것을 확인했다.</p>
<h2 id="taskjob">TaskJob</h2>
<h3 id="task-1-헤더-생성">task 1) 헤더 생성</h3>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/b322089e-2c96-4c68-a805-d89c75ecc862/image.gif" alt="">
웹페이지 로고를 누르면 메인 페이지로 돌아간다.
마켓, NFT민팅, 마이페이지 내비게이션 버튼이 있다.
지갑 연결 버튼이 있다.</p>
<h3 id="task-2-메인-페이지-랜딩-페이지">task 2) 메인 페이지 (랜딩 페이지)</h3>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/20dfa7bf-098a-47e5-b6b5-6a02217a421a/image.gif" alt="">
NFT 리스트가 있다.
10페이지 단위씩 볼 수 있도록 페이지네이션으로 개발한다.
게시글 제목에 커서를 대면 커서가 누르는 모양으로 바뀌어야 한다.
서버에서 NFT 리스트 데이터를 받아와야 한다.</p>
<h3 id="task-3-nft-민팅-페이지">task 3) NFT 민팅 페이지</h3>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/a07509f9-e0be-4355-9098-f21a12311314/image.gif" alt=""><img src="blob:https://velog.io/1e594553-a1a4-4cb7-b0ed-ec25dc6a7201" alt="업로드중..">
이미지, 이름, 상세내용 칸이 있다.
리액트에서 제공하는 기본 폼으로 NFT 민팅 페이지를 개발했다.
<img src="https://velog.velcdn.com/images/nft_sb/post/862f69b7-453c-4177-b63f-4244504fc3a2/image.png" alt=""></p>
<p>민팅 버튼을 누르면, 지갑 서명 통해 트랜잭션을 수행하도록 한다.</p>
<h3 id="task-4-테마별-nft-리스트-페이지">task 4) 테마별 NFT 리스트 페이지</h3>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/c2aaa0f0-0447-476f-a476-22f88a153bfc/image.gif" alt="">
NFT 이미지와 작가 이름 존재한다.
탭 기능 사용하여 테마별 NFT 리스트 조회가 가능해야 한다.
목록 버튼을 누르면 게시글 리스트의 클릭했던 목록으로 돌아간다.</p>
<h3 id="task-5-nft-상세-페이지">task 5) NFT 상세 페이지</h3>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/a95ee552-3837-4c4f-a744-8919cfbd18c9/image.gif" alt="">
이미지를 포함한 NFT 상세 정보를 보여줄 수 있다.
거래되는 가격을 보여줄 수 있다.
<img src="https://velog.velcdn.com/images/nft_sb/post/25acb9fd-75a8-46b0-8296-1b6a60c9620b/image.gif" alt="">
구입버튼을 누르면 지갑을 통해 트랜잭션을 수행한다.</p>
<h3 id="task-6-마이-페이지">task 6) 마이 페이지</h3>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/470fa00b-91bf-4aad-b92a-b6d038c9b1e7/image.gif" alt="">
프로필, 보유한 NFT, 발행한 NFT 를 볼 수 있다.
지갑 연결을 해제할 수 있다</p>
<h2 id="feeling">Feeling</h2>
<p>망각이 축복이라고 하지만 기술적인 부분에서는 해당되지 않아 유감이다.
방대한 학습량에 비례해서 단숨에 역량을 올린다는것이 불가능 할 줄 알았지만, 오히려 정리되지 않는 학습내용은 에러와 고민을 늘릴 뿐이다.
하지만 직접 만드는 행위가 자연스럽게 이론이 프로젝트에 녹아서 내 것이 되는 것을 느꼈다.</p>
<h2 id="finding">Finding</h2>
<p>재앙
CSS의 루트를 짜 놓지 않는 바람에 
컬러를 통일감 있게 주기 위해 약간의 시간이 허비 된것은 차치하고,</p>
<p>순진한 생각으로 H1~H6태그에 직접 CSS를 적용하여 마진과 패딩값을 준 것이 
메인 페이지 이후 서브 페이지 구축할 때에 수 많은 문제를 일으켰다. </p>
<p>걸핏하면 제 멋대로 박스와 버튼을 벗어났고 컬러 변경 적용되지 않았으며 
특히 정렬문제와 패딩 마진 값이 동시다발적으로 충돌을 일으킬 때에는 
처음부터 다시 만들어야 하나 하는 고민을 하게 만들었다.</p>
<p>그리하여 NFT 컴포넌트를 만들 때에는 4시간 정도 잡고 헤매다, 
결국 관련 CSS를 모두 밀어버리고 처음부터 다시 적용시켰다. 
시간적 여유가 없어 애니메이션과 트랜스폼스 효과와 반응형 웹 효과를 주기에는 
시간이 부족했고 단순 호버링 효과만 적용할 수 밖에 없었던 점이 아쉬웠다.</p>
<p>디자인 요소에도 아쉬움이 많지았만 무엇보다 리액트에 대한 망각이 큰 부담으로 다가왔다.
State 와 props를 통한 데이터 흐름을 다시 파악하고 구조를 정하는 데 시간이 걸렸다.</p>
<h2 id="future-action">Future Action</h2>
<p>앞으로 더 고민해 볼 부분이 있다.
git stash 
git pull pair main
git stash pop</p>
<p>현재로서는 이 방법으로 충돌을 해결하는 방법 밖에는 알지 못한다.
그러나 이렇게 스택을 pop하고 난 후에는 데이터가 보존되지 않기 때문에 안전성에 결함이 있을 것으로 예상된다. 다음 프로젝트가 시작 되기전에 알아 볼 내용이다.</p>
<p>모든 프로젝트가 끝난 후에 리팩토링 해보자.</p>
<p>다음에는 트랜젝션과 백엔드 쪽에서도 기여를 해 보고 싶다.
mysql나 mongoDB로 백엔드를, 그리고 soliditiy로 트랜젝션 개발에 기여해 보고 싶다.</p>
<p>다음 프로젝트는 인샌티브 기반 커뮤니티이다. 
당장 기획해서 이번 프로젝트 이상의 결과물을 만들어 낼 수 있도록 진행 해 보자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[깃 허브 브랜치 명령어 모음]]></title>
            <link>https://velog.io/@nft_sb/%EA%B9%83-%ED%97%88%EB%B8%8C-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AA%A8%EC%9D%8C</link>
            <guid>https://velog.io/@nft_sb/%EA%B9%83-%ED%97%88%EB%B8%8C-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AA%A8%EC%9D%8C</guid>
            <pubDate>Wed, 21 Dec 2022 02:32:12 GMT</pubDate>
            <description><![CDATA[<p>브랜치 명령어 모음
새로운 브랜치 생성
$ git branch 새로운 브랜치 이름
새로운 브랜치 생성 후 해당 브랜치로 전환
$ git switch -c 새로운 브랜치 이름
$ git checkout -b 새로운 브랜치 이름
브랜치 목록 확인
$ git branch
브랜치 목록과 각 브랜치의 최근 커밋 확인
$ git branch -v
브랜치 삭제
$ git branch -d 삭제할 브랜치 이름
$ git branch -D 해당 명령어는 병합하지 않은 브랜치를 강제 삭제하는 방법입니다.
브랜치 전환
$ git switch 브랜치 이름
$ git checkout 브랜치 이름
브랜치 병합
master 브랜치로 dev 브랜치를 병합할 때 (master ← dev)
$ git checkout master
$ git merge dev
로그에 모든 브랜치를 그래프로 표현
$ git log --branches --graph --decorate
아직 commit 하지 않은 작업을 스택에 임시로 저장
$ git stash</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[블록체인: 스마트 컨트랙트 문법]]></title>
            <link>https://velog.io/@nft_sb/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EC%8A%A4%EB%A7%88%ED%8A%B8-%EC%BB%A8%ED%8A%B8%EB%9E%99%ED%8A%B8-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@nft_sb/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EC%8A%A4%EB%A7%88%ED%8A%B8-%EC%BB%A8%ED%8A%B8%EB%9E%99%ED%8A%B8-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Mon, 28 Nov 2022 09:23:34 GMT</pubDate>
            <description><![CDATA[<p>스마트 컨트랙트를 만들기 위해서 특별한 게 필요한 것은 아니다. 스마트 컨트랙트는 사실 우리가 배웠던 다른 개발 언어와 비슷하며, 다만 블록체인 위에서 구동하기 위해 만들어진 부분에 대한 차이가 있을 뿐이다.</p>
<h2 id="컨트랙트-구조">컨트랙트 구조</h2>
<pre><code>상태 변수(State Variables)
구조체(Struct Types)
열거형(Enum Types)
함수(Functions)
함수 제어자(Function Modifiers)
이벤트(Events)
에러(Errors)
상속(inheritance)</code></pre><h1 id="솔리디티solidity">솔리디티(Solidity)</h1>
<h3 id="객체-지향-프로그래밍-언어">객체 지향 프로그래밍 언어</h3>
<p>이더리움 블록체인 플랫폼에서 다양한 스마트 컨트랙트(계약 로직)를 작성할 때 사용
ex) 투표, 크라우드 펀딩, 블라인드 경매, 다중 서명 지갑 등</p>
<pre><code>정적 타입의 중괄호 언어
솔리디티는 정적 타입(static-typed)의 중괄호(curly-braces) 프로그래밍 언어
자바스크립트와 달리 컴파일 시에 변수에 타입이 결정
그렇기에 소스 코드에 타입을 명확하게 정의해 줘야 함

튜링 완전 언어
이더리움은 gas를 통한 과금 메커니즘을 도입하여 
블록체인 네트워크에서 튜링 완전 언어를 실현
솔리디티는 비트코인 스크립트와 다르게 반복문 등의 작업을 수행 가능
이더리움 네트워크에서 다양한 스마트 컨트랙트를 구현하는 기반이 됨

세미콜론(;)
마지막으로 솔리디티는 문장의 끝에 반드시 세미콜론(; )을 붙여야 함
세미콜론은 문장의 끝을 구분해주는 역할을 하여, 이를 붙이지 않을 시
컴파일 에러가 발생    </code></pre><h2 id="spdx-license-identifier">SPDX License Identifier</h2>
<p>스마트 컨트랙트에 대한 신뢰를 높임
저작권과 같은 문제를 해소하기 위해 솔리디티 코드의 최상단에 SPDX 라이센스를 명시</p>
<h3 id="spdx-라이센스는-주석으로-표기">SPDX 라이센스는 주석으로 표기</h3>
<pre><code>// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: GPL-3.0</code></pre><p>SPDX 라이센스 리스트는 <a href="https://spdx.org/licenses/">https://spdx.org/licenses/</a> 에서 확인할 수 있습니다.</p>
<h2 id="pragma">Pragma</h2>
<p>pragma 키워드는 특정 <strong>컴파일러의 버전을 표기할 때 사용</strong></p>
<p>솔리디티 컴파일러와의 호환성을 지칭하는 것
<strong>“이 코드에서는 해당 버전의 컴파일러가 필요하다&quot;</strong>라는 것을 명시</p>
<p>pragma는 <strong>모든 소스 코드 파일</strong>에 있어야 함 
다른 파일을 임포트 하더라도, pragma는 <strong>자동으로 임포트 되지 않음</strong></p>
<p>일반적으로 다음과 같이 <strong>코드 최상단</strong>에 작성합니다.</p>
<pre><code>// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.14;  // 0.8.14 버전을 사용</code></pre><p><strong>특정 버전 이상</strong>의 pragma를 사용할 때는 ^</p>
<pre><code>// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.14;  // 0.8.14 이상의 버전을 사용
// SPDX-License-Identifier: GPL-3.0
pragma solidity &gt;=0.4.0 &lt;0.9.0; // 0.4.0 이상 0.9.0 미만의 버전을 사용</code></pre><p>그 외에도 다양한 버전 규칙을 사용할 수 있으며,** 버전 규칙은 npm 문법과 동일**
<strong>npm 버전 규칙</strong>: <a href="https://docs.npmjs.com/cli/v6/using-npm/semver">https://docs.npmjs.com/cli/v6/using-npm/semver</a></p>
<h2 id="contract">Contract</h2>
<p>솔리디티 계약은 이더리움 블록체인의
<strong>특정 주소를 가진 기능</strong>(코드)와 <strong>상태</strong>(데이터)의 모음
여기서 특정 기능은 함수로 표현, 상태는 변수로 표현
일반적인 객체 지향 언어의 클래스를 정의하듯
하나의 <strong>contract(계약)</strong>를 정의</p>
<pre><code>contract SimpleStorage {
    uint storedData; // 상태 변수

        // 함수
    function set(uint x) public {
        storedData = x;
    }
        // 함수
    function get() public view returns (uint) {
        return storedData;
    }
}</code></pre><h2 id="import">Import</h2>
<p>파일을 임포트 하는 방식은 자바스크립트에서 사용하는 방식과 동일</p>
<pre><code>import &quot;파일이름&quot;;

// 임포트하는 파일을 symbolName이라는 이름으로 사용
import * as symbolName from &quot;파일이름&quot;;
import &quot;파일이름&quot; as symbolName;

// 파일의 일부분만 임포트 하는 경우
import {symbol1 as alias, symbol2} from &quot;파일이름&quot;;</code></pre><h2 id="주석">주석</h2>
<p><strong>단일 라인 주석 처리</strong>는(//), <strong>여러 라인 주석 처리</strong>는(/<em>...</em>/)로 진행합니다.</p>
<pre><code>// 단일 라인 주석입니다.

/*
이것은
여러 라인 주석입니다.
*/</code></pre><h2 id="변수">변수</h2>
<h3 id="데이터-저장-위치">데이터 저장 위치</h3>
<p>보통의 프로그래밍 언어라면 변수는 스택, 힙 등 메모리에 저장되는 것이 기본
솔리디티는 변수를 메모리뿐 아닌 하드 디스크 등과 같은 스토리지에 저장하기도 함
또한 calldata 라는 영역에 저장하기도 하는데, 여기에는 함수 인자가 저장
calldata 역시 메모리처럼 동작하지만 수정 불가능하고 비영구적인 영역</p>
<h4 id="솔리디티의-데이터-저장-위치">솔리디티의 데이터 저장 위치</h4>
<pre><code>메모리
스토리지    
calldata</code></pre><h4 id="강제-데이터-위치">강제 데이터 위치</h4>
<pre><code>외부 함수의 매개 변수(반환 값 미포함): calldata
상태 변수: 스토리지</code></pre><h4 id="기본-데이터-위치">기본 데이터 위치</h4>
<pre><code>함수의 매개변수(반환 값 포함): 메모리
모든 지역 변수: 스토리지</code></pre><h2 id="변수의-종류">변수의 종류</h2>
<p>솔리디티에서 변수는 크게 <strong>상태변수</strong>, <strong>지역변수</strong>, <strong>전역변수</strong>로 나누어진다.
상태변수와 지역변수는 일반적인 프로그래밍 언어에서의 변수를 생각하면 된다.</p>
<p><strong>선언 및 초기화 방식</strong></p>
<pre><code>{데이터타입} {변수명}; // 변수명으로 선언
{데이터타입} {변수명} = {초기화할 값};  // 선언 및 초기화</code></pre><p>전역변수는 솔리디티만의 특수한 변수(또는 함수)로써 주로 블록체인에 관한 정보를 제공합니다.</p>
<p>전역변수는 block.number(현재 블록의 번호), msg.sender(Tx 송신자의 address) 등 컨트랙트를 생성할 당시에는 알 수 없는 블록체인에 관한 정보를 제공하여 컨트랙트의 사용성을 높여줍니다.</p>
<p>전역변수는 따로 선언이나 초기화 없이 불러와서 사용합니다.</p>
<h3 id="상태변수">상태변수</h3>
<p>상태변수란 컨트랙트 저장소(이더리움 블록체인)에 영구적으로 저장되는 변수를 말합니다.
즉, 항상 스토리지에 저장됩니다.
보통 컨트랙트  최상위 단에 선언합니다.</p>
<p>1
2
3
4
5
6
pragma solidity ^0.8.14;</p>
<p>contract SimpleStorage {
    uint storedData; // 상태변수 선언
    uint storedData2 = 20; // 상태변수 선언 및 초기화
}
세부적인 자료형에 대해서는 이후에 다룹니다.</p>
<h3 id="상태-변수-접근-수준">상태 변수 접근 수준</h3>
<p>컨트랙트 내의 상태(state) 변수를 선언할 때는 지정할 수 있는 접근 수준을 함께 표기합니다.</p>
<p>접근 수준은 public, internal, private, constant / immutable, 네 가지로 나뉩니다.</p>
<p>internal(default):
상태 변수에 기본적으로 사용
컨트랙트 및 해당 컨트랙트를 상속받은 컨트랙트만 접근 가능
외부에서 액세스 불가능
public:
컴파일러가 자동으로 getter 함수를 생성해줌
컨트랙트 내에서 직접 퍼블릭 상태 변수를 사용 가능
외부 컨트랙트나 클라이언트 코드에서도 getter 함수를 통해 퍼블릭 상태 변수에 접근 가능
private:
동일한 컨트랙트 멤버만 프라이빗 상태 변수에 접근 가능
constant / immutable:
선언될 때 값을 할당해야 함
상수화 = 변경 불가능</p>
<h3 id="지역변수">지역변수</h3>
<p>지역변수란 함수가 실행될 때까지만 존재하는 변수
지역변수 역시 기본값으로는 스토리지에 저장(레퍼런스 타입의 경우 재정의 가능)
보통 함수 아래에 선언되는 변수</p>
<pre><code>pragma solidity ^0.8.14;

contract SimpleStorage {
    ...
        function simpleFunction() public pure returns(uint) {
        uint a; //  지역변수 선언
            uint b = 1; // 지역변수 선언 및 초기화
            a = 1;
            uint result = a + b;
            return result;
        }
}</code></pre><h3 id="전역변수">전역변수</h3>
<p>전역변수란 글로벌한 블록체인 안에 있는 특수 변수
블록체인 및 트랜잭션에 대한 속성을 가지고 올 수 있음</p>
<pre><code>function f(uint start, uint daysAfter) public {
    if (block.timestamp &gt;= start + daysAfter * 1 days) {
      // 여기서 block.timestamp는 전역변수
    }
}</code></pre><p>block: 블록에 대한 정보를 가지고 있습니다.
msg: 컨트랙트를 시작한 트랜잭션 콜이나 메시지 콜에 대한 정보를 가지고 있습니다.
tx: 트랜잭션 데이터를 가지고 있습니다.
This: 현재 컨트랙트를 참조합니다. 현재 컨트랙트 주소로 암시적으로 변환됩니다.</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/078bea89-8c8a-448c-9a17-ea0dbe7d1859/image.PNG" alt=""></p>
<h2 id="자료형">자료형</h2>
<pre><code>값 형 데이터 타입(Value Types)
참조형 데이터 타입(Reference Types)</code></pre><p><img src="https://velog.velcdn.com/images/nft_sb/post/9ce6cc8b-5aaa-4025-9cde-4e628658043a/image.png" alt=""></p>
<h3 id="값-형-데이터-타입value-types">값 형 데이터 타입(Value Types)</h3>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/58f20d5c-1085-456c-be3b-c976ece8245a/image.png" alt=""></p>
<h3 id="1-불bool">1. 불(bool)</h3>
<p>bool(boolean)로 선언된 변수는 true나 false 값을 가집니다.</p>
<pre><code>bool isOpen = true;
bool isSold = false;</code></pre><h3 id="2-정수int-uint">2. 정수(int, uint)</h3>
<p>정수의 경우에는 int, 0을 포함한 양의 정수 값에는 uint를 사용합니다.</p>
<p>int, uint 뒤에 8 ~ 256의 8의 배수의 숫자를 붙여 변수의 크기를 비트 단위로 지정할 수도 있습니다.
(예. int8, int16, int24, uint64, uint128, …)</p>
<p>각 숫자에 따라 정수는 특정 범위로 제한됩니다.
int16는 -32768<del>32767 사이의 정수를 의미하며, uint16은 0</del>65535 사이의 정수를 의미합니다.</p>
<p>일반적으로 뒤에 숫자가 없는 int, utint는 int256, uint256을 의미합니다.</p>
<pre><code>int8 seoulTemp = -20
uint16 myAge = 30</code></pre><h3 id="3-주소address">3. 주소(address)</h3>
<p>주소 타입은 크게 두 가지 유형으로 나뉩니다.</p>
<p>address: 20바이트의 이더리움 주소 값을 가짐
address payable: address와 동일한 값을 가지지만 추가 멤버인 transfer, send를 가짐
주소(address) 객체는 0x로 시작하고 최대 40자리의 16진수로 구성되는 문자열을 값으로 가집니다.</p>
<pre><code>address yourAddress = 0x10abb5efEcdc01234f7b2384912398798E089Ab2;</code></pre><p>중요한 것은, 0.8 버전부터 address 형식은 송금이 불가능한 주소값이라는 점입니다.</p>
<p>스마트 컨트랙트에서 특정 주소 값으로 송금하기 위해서는 address payable 형식을 사용해야 합니다. address payable 형식에는 이더 송금을 위한 transfer()와 send() 함수가 내장되어 있습니다.</p>
<p>address 형식 데이터를 payable() 함수에 인자로 담아 address payable 형식 데이터를 만들 수 있습니다.</p>
<pre><code>address addr1;
address payable p_addr1 = payable(addr1);</code></pre><p>uint160 또는 bytes20 형식의 데이터를 address payable로 바꾸기 위해서는 먼저 address()를 사용하여 주소 형태로 만들고, 다시 payable()을 사용해 address payable 형식으로 바꿀 수 있습니다.</p>
<pre><code>uint160 num;
address addr = address(num);
address payable p_addr = payable(addr);</code></pre><p>컨트랙트를 address payable로 변환할 수도 있습니다.</p>
<p>만약 컨트랙트가 이더를 받을 수 있는 컨트랙트인 경우,
address(컨트랙트)를 수행했을 때 address payable 형식의 주소값을 반환합니다.</p>
<pre><code>contract C  {  // 이더를 받을 수 있는 컨트랙트
    constructor () payable { }
}
address payable addr = address(C);  // address(C)는 address payable 형식의 주소값을 반환한다</code></pre><p>반면, 컨트랙트가 이더를 받지 않는 컨트랙트인 경우,
address(컨트랙트)를 수행했을 때 address 형식의 주소값을 반환합니다.</p>
<p>이 경우 결과값을 payable()에 넣어 address payable 형식으로 만들 수 있습니다.</p>
<pre><code>contract D {. // 이더를 받지 않는 컨트랙트
     constructor () { }
}

address addr = address(D); // address(D)는 address 형식의 주소값을 반환한다
address payable addr_p = payable(addr); // payable()을 사용해 address payable 형식의 주소값을 만들 수 있다.</code></pre><h3 id="4-바이트-배열고정-크기">4. 바이트 배열(고정 크기)</h3>
<p>데이터를 바이너리 형태로 저장하기 위해 사용합니다.
bytes1 ~ bytes32까지의 고정된 크기의 배열을 선언합니다.
정해진 바이트 크기와 값의 크기가 다르면 에러가 납니다.</p>
<pre><code>bytes3 alphabets = &#39;abc&#39;;

alphabets[0] // &#39;a&#39;
alphabets[1] // &#39;b&#39;
alphabets[2] // &#39;c&#39;</code></pre><p>바이트 배열(가변 크기)는 참조형 타입으로 추후 다룹니다.</p>
<h3 id="5-열거형enum">5. 열거형(enum)</h3>
<p>열거형(enum)은 특정 값들로 집합을 지정하고, 집합에 있는 데이터만을 값으로 가집니다.
각 집합의 데이터는 내부적으로는 순서에 따라 0부터 1씩 올라가는 정수를 값으로 가집니다.</p>
<pre><code>enum EvalLevel { Bad, Soso, Great } // 열거형 집합을 지정합니다.
EvalLevel kimblock = EvalLevel.Bad // 열거형으로 변수를 선언합니다.
int16 kimblockValue = int16(kimblock); // kimblock 열거형 값 0을 정수형으로 변환합니다.</code></pre><p>추가적으로 (u)fixedMxN 형식으로 표현되는 고정소수점 타입이 존재하지만 현재 솔리디티에서는 완전히 지원되지 않기에 다루지 않았습니다.</p>
<p>참고: <a href="https://docs.soliditylang.org/en/v0.8.14/types.html#fixed-point-numbers3">https://docs.soliditylang.org/en/v0.8.14/types.html#fixed-point-numbers3</a></p>
<h2 id="참조형-데이터-타입reference-types">참조형 데이터 타입(Reference Types)</h2>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/26230e66-0286-4ceb-9089-87b6073ee6a4/image.png" alt=""></p>
<p>참조형 변수(reference type)는 마치 배열과 같이, 연속되어 저장되는 값의 첫번째 메모리의 주소를 값으로 가지는 변수 타입입니다. 이를 &#39;참조한다&#39;라고 표현합니다.</p>
<p>데이터 저장 영역에는 세 종류가 있다고 위에서 다룬 적이 있습니다.</p>
<pre><code>메모리: 프로그램이 동작하는 동안에만 값을 기억하고, 종료되면 값을 잃는 데이터 영역
스토리지: 블록체인에 기록되어 영구적으로 값이 유지되는 데이터 영역
calldata: 메모리와 비슷하지만 수정 불가능하고 비영구적인 데이터 영역</code></pre><p>참조형 변수를 선언할 때는 메모리에 저장할지 스토리지에 저장할지 명시해야 합니다.</p>
<p>(상태변수는 무조건 스토리지에 저장됩니다.)</p>
<pre><code>function f() {
     // 5개의 int32 형태의 데이터를 메모리에 저장하는 변수 fixedSlots 선언
    int32[5] memory fixedSlots;
    fixedSlots[0] = 13;
}</code></pre><p>참조형 변수의 유형은 다음과 같습니다.</p>
<pre><code>배열(Array)
바이트 배열(가변 크기, Dynamically-sized byte array)
문자열(String)
구조체(Struct)
매핑(Mapping)</code></pre><h3 id="1-배열array">1. 배열(array)</h3>
<p>배열(array)은 저장하고자 하는 데이터 형식에 []를 붙여 선언합니다.</p>
<p>가령 uint8 형식의 데이터를 저장하는 배열을 만드는 경우, uint8[]과 같이 자료형을 작성합니다.</p>
<p>배열에는 정적 배열과 동적 배열이 존재합니다.</p>
<pre><code>정적 배열: uint[4] {배열 이름} 과 같은 형식으로 사용할 배열의 크기를 지정하여 선언합니다.
동적 배열: uint[] {배열 이름} 과 같은 형식으로 배열의 크기를 지정하지 않고 선언합니다.
        5개의 동적 배열로 구성된 배열은 uint[][5]로 작성됩니다.</code></pre><p>new 키워드를 사용해 동적 배열을 메모리에 할당할 수도 있습니다.</p>
<h4 id="1-2-바이트-배열가변-크기">1-2. 바이트 배열(가변 크기)</h4>
<p>바이트(bytes)는 특수한 형태의 배열입니다.
고정 크기 바이트배열과 다르게 크기를 정해놓지 않고, 입력값에 따라 크기가 달라집니다.</p>
<p>bytes로 가변 크기의 배열을 선언합니다.</p>
<pre><code>    bytes alphabets = &#39;abc&#39;;</code></pre><h4 id="1-3-문자열string">1-3. 문자열(string)</h4>
<p>문자열(string) 역시 특수한 형태의 배열로써, 바이트 배열(가변 크기)에 기반한 문자열 타입입니다.</p>
<p>string은 bytes와 동일하지만, index, push, length, concat 등을 지원하지 않습니다.
문자열 리터럴로 초기화합니다.</p>
<pre><code>string name = &#39;kimblock&#39;;</code></pre><h3 id="2-구조체struct">2. 구조체(struct)</h3>
<p>구조체(struct)는 서로 다른 유형의 항목을 포함하는 집합으로, 사용자 정의 형식입니다.
구조체는 배열과 매핑의 내부에서 사용될 수 있으며, 반대로 구조체에 배열과 매핑을 포함할 수도 있습니다.</p>
<p>하지만 구조체가 동일한 구조체 타입의 멤버를 포함할 순 없습니다.</p>
<p>구조체는 다음과 같이 정의합니다.</p>
<pre><code>contract exmapleC {
    struct User {
        address account;
        string lastName;
        string firstName;
            mapping (uint =&gt; Funder) funders;
    }

    mapping (uint =&gt; User) users;
}</code></pre><p>구조체를 사용할 때는 각 항목에 대한 값을 객체 형식으로 추가합니다.</p>
<pre><code>contract exmapleC {

    struct User {
        address account;
        string lastName;
        string firstName;
    }

    function newUser (address newAddress, string newLastName, string newFirstName){
        User memory newOne = User({account: newAddress, lastName: newLastName, firstName: newFirstName});
    }
}</code></pre><h3 id="3-매핑mapping">3. 매핑(mapping)</h3>
<p>매핑(mapping)은 스토리지 데이터 영역에서 키-값 구조로 데이터를 저장할 때 사용하는 참조형입니다.</p>
<p>mapping(키 형식=&gt; 값 형식) 변수명 형태로 선언합니다.</p>
<p>여기서 키 형식은 매핑, 구조체, 배열 제외한 유형의 값이 다 될 수 있습니다.</p>
<p>여기서 키, 값 형식은 매핑, 구조체, 배열을 포함한 모든 유형의 값이 다 될 수 있습니다.</p>
<pre><code>mapping(address =&gt; int) public userAddress;</code></pre><p><img src="https://velog.velcdn.com/images/nft_sb/post/5bb36e50-1157-40e9-9264-da4310ee1e1a/image.png" alt=""></p>
<p>매핑은 일반적인 프로그래밍 언어에서의 해시 테이블 또는 딕셔너리(자바스크립트는 객체)와 유사합니다.</p>
<p>키 자체가 실제로 저장되지는 않고, 키의 keccak256 해시를 이용해 값에 접근합니다.</p>
<p>매핑은 오직 스토리지 영역에만 저장될 수 있으므로 상태 변수, 내부 함수에서의 스토리지 참조 타입, 라이브러리 함수의 매개 변수에만 허용됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Ready_for_Project]]></title>
            <link>https://velog.io/@nft_sb/ReadyforProject</link>
            <guid>https://velog.io/@nft_sb/ReadyforProject</guid>
            <pubDate>Sat, 26 Nov 2022 07:42:20 GMT</pubDate>
            <description><![CDATA[<h1 id="참고할만-한-프로젝트-사례">참고할만 한 프로젝트 사례</h1>
<p>프로젝트 미리 준비하시는 BEB 7기 분들 참고하시면 좋을 만한 글을 정리해서 올립니다.
BEB 1기 부터 6기 순으로 정리했습니다.</p>
<h2 id="beb-1기-김기대님의-프로젝트">BEB 1기 김기대님의 프로젝트</h2>
<h3 id="오픈씨-클론코딩">오픈씨 클론코딩</h3>
<p><a href="https://github.com/kgd7054/BEB_01_ToTheMoon">오픈씨 클론코딩 깃허브</a></p>
<h3 id="인센티브-기반-커뮤니티">인센티브 기반 커뮤니티</h3>
<p><a href="https://github.com/kgd7054/BEB_01_OlderAgain">인센티브 기반 커뮤니티 깃허브</a> </p>
<h3 id="파이널-프로젝트">파이널 프로젝트</h3>
<p><a href="https://github.com/kgd7054/BEB_01_final3">컨텐츠 배팅 프로젝트 깃허브</a></p>
<h2 id="beb-3기-이주영님의-belugasea">BEB 3기 <a href="https://velog.io/@be-kid/BEB-section5-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-1">이주영</a>님의 BelugaSea</h2>
<h3 id="belugasea">BelugaSea</h3>
<p><a href="https://beb-03-beluga.vercel.app/">BelugaSea프로젝트 배포</a> 
<a href="https://github.com/codestates/beb-03-beluga">BelugaSea프로젝트 깃허브</a> </p>
<h3 id="코드-콜로세움">코드 콜로세움</h3>
<p>이 분의 파이널 프로젝트인 코드 콜로세움도 보시면 좋을 것 같네요.
<a href="https://codecolosseum.netlify.app/">코드 콜로세움 프로젝트 배포</a></p>
<h2 id="beb-4기-peoplechain의-파이널-프로젝트">BEB 4기 PeopleChain의 파이널 프로젝트</h2>
<h3 id="memint">MEMINT</h3>
<p>토큰 이코노미 데이팅 앱 구현 (디자인너 출신이 한 분 있으신 듯)
임혜정님의 <a href="https://velog.io/@mae-zung">블로그</a>
이종석님의 <a href="https://chacot.tistory.com/">블로그</a>
김성현님의 <a href="https://www.notion.so/78b1125facd14686b6d0bed57d956e4a">블로그</a>
조은민님의 <a href="https://blog.naver.com/silvermn99">블로그</a>
<a href="https://github.com/codestates/BEB-04-PeopleChain">MEMINT프로젝트 깃 허브 </a></p>
<h2 id="beb-5기-종덱스팀의-파이널-프로젝트">BEB 5기 종덱스팀의 파이널 프로젝트</h2>
<h3 id="jdex">JDEX</h3>
<p>Klaytn 기반의 DEX(탈중앙화거래소) 구현.
<a href="https://github.com/codestates/BEB-05-JDEX">JDEX프로젝트 깃허브</a></p>
<h2 id="beb-6기-곽규명님의-프로젝트2">BEB 6기 곽규명님의 프로젝트2</h2>
<h3 id="인센티브-기반-커뮤니티-1">인센티브 기반 커뮤니티</h3>
<p><a href="https://github.com/hd3946/BEB-06-SECOND-04">인센티브 기반 커뮤니티 깃허브</a></p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/0ac2bc0b-92ba-4b16-b5f6-51cddb61695b/image.jpg" alt=""></p>
<p>준비 잘 하셔서 굉장한 프로젝트로 마무리 하시기를 바랍니다.</p>
<h4 id="7기-화이팅">7기 화이팅</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[Signup_Validation]]></title>
            <link>https://velog.io/@nft_sb/SignupValidation</link>
            <guid>https://velog.io/@nft_sb/SignupValidation</guid>
            <pubDate>Sat, 26 Nov 2022 04:42:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nft_sb/post/4129a256-37c0-4977-9811-aadbff0e6984/image.gif" alt=""></p>
<h2 id="js브라우저-dom으로-유효성-검사를-한다">[JS/브라우저] DOM으로 유효성 검사를 한다.</h2>
<p><a href="https://github.com/Russ481-k/mini_Projects/tree/main/signUp">Signup_Validation 깃허브</a></p>
<h3 id="재미있는-것을-해야-하는-법이다">재미있는 것을 해야 하는 법이다.</h3>
<p>해외 가상자산 투자 플랫폼의 회원가입 페이지를 참고하여 
유효성 검사 페이지를 만들었다.</p>
<h3 id="목표">목표</h3>
<p>정규표현식을 활용
media 쿼리를 통한 반응형 웹
Signup_Validation 페이지 구현
이메일 형식을 확인
비밀번호 형식을 확인</p>
<h3 id="페이지-구성">페이지 구성</h3>
<pre><code>welcome image
Create Account
    Country of residence 국가 (select, option)
    입력(input)
        Email
        Mobile number
    이용약관(checkbox)
        I agree to the &lt;Terms of Use&gt;
    회원가입 버튼
    구글, 애플
    로그인</code></pre><h3 id="dom으로-html-조작">DOM으로 HTML 조작</h3>
<pre><code>CREATE - createElement
APPEND - append, appendChild
READ - querySelector, querySelectorAll
UPDATE - textContent, classList.add
DELETE - remove, removeChild</code></pre><p><img src="https://velog.velcdn.com/images/nft_sb/post/d0850951-317f-41df-855f-eeb8d9afedb3/image.jpg" alt=""></p>
<h3 id="이메일-유효성-검사">이메일 유효성 검사</h3>
<h4 id="html">html</h4>
<pre><code class="language-html">&lt;div class=&quot;email&quot;&gt;
    &lt;input type=&quot;text&quot; placeholder=&quot;Email&quot; id=&quot;username&quot;&gt;
    &lt;div&gt;
        &lt;div class=&quot;failure_message wrong_id hide&quot;&gt;
        //유효성 검사를 위해 failure_message에 클래스로 hide를 추가해 준다. 
            &lt;h6&gt;
                  The account you entered (mail or phone number)
                is in the wrong format
              &lt;/h6&gt;
          &lt;/div&gt;
        &lt;div class=&quot;failure_message none_id hide&quot;&gt;
            &lt;h6&gt;Enter Email address&lt;/h6&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;</code></pre>
<h4 id="css">css</h4>
<p>hide 클래스를 추가하고 제거함으로 
css에서 해당 클래스를 display: none; 설정하여 
일정 조건 하에서 페이지 상에 출력 여부를 선택할 수 있도록 한다.</p>
<pre><code class="language-css">    .hide {
        display: none;
    }
</code></pre>
<h4 id="javascript">javascript</h4>
<pre><code class="language-javascript">let elInputUsername = document.querySelector(&#39;#username&#39;)
//elInputUsername 변수를 선언하고 
//document.querySelector를 통해 (&#39;#username&#39;)로 엘리먼트를 선택한다.
elInputUsername.onkeyup = function() { //함수를 선언한다.

    if(emailFormat(elInputUsername.value)){
    //함수를 통해 들어오는 값은 emailFormat함수로 들어간다
        elWrongIdMessage.classList.add(&#39;hide&#39;)
          //그 값의 결과가 true이면 elWrongIdMessage.classList.add(&#39;hide&#39;)를 통해
          //실패 메세지에 hide클래스를 추가하여 메세지를 숨긴다. 
    }else{
      //그 값의 결과가 false이면 elWrongIdMessage.classList.remove(&#39;hide&#39;)를 통해
      //해당 실패 메세지에 hide클래스를 삭제한다.
        if(elInputUsername.value){
            elNoneIdMessage.classList.add(&#39;hide&#39;)
            elWrongIdMessage.classList.remove(&#39;hide&#39;)

        }else{
            elNoneIdMessage.classList.remove(&#39;hide&#39;)
            elWrongIdMessage.classList.add(&#39;hide&#39;)
              //입력값이 없을 경우에는 입력 요구 메세지를
            //입력값의 형식이 잘못 되었을 경우에는 형식 요구 메세지를 
            //출력할 수 있도록 했다.
        }
    }
}

function emailFormat(value){
    return value.includes(&#39;@&#39;&amp;&amp;&#39;.&#39;) 
      //emailFormat함수는 들어 오는 값에 &#39;@&#39;와 &#39;.&#39;이 반드시 포함되어 
    //이메일 형식이 갖춰 질 경우에 true를 반환하도록 한다. 
}</code></pre>
<p>위와 같은 방법으로 비밀번호 유효성 검사를 추가했다
비밀번호는
    8~32의 글자로 구성
    1개 이상의 숫자 포함 (/[0-9]/g)
    1개 이상의 특수문자 (/[@#$%^&amp;+!=]/g)
    1개 이상의 대문자가 포함(/[A-Z]/g)</p>
<p>위와 같이 정규 표현식을 사용했다.</p>
<pre><code class="language-javascript">function pwFormatLength(value){
    return 8 &lt;= value.length &amp;&amp; value.length &lt;= 32
}

function pwFormatLeastNum(value){
    if(value.match(/[0-9]/g)){
        return true
    }else{
        return false
    }
}

function pwFormatUppercase(value){
    if(value.match(/[A-Z]/g)){
        return true
    }else{
        return false
    }

}

function pwFormatSpecial(value){
    if(value.match(/[@#$%^&amp;+!=]/g)){
        return true
    }else{
        return false
    }}</code></pre>
<h2 id="그리고-그-다음">그리고 그 다음</h2>
<p> 그래서 다음 미니 프로젝트에서는 애니메이션 효과를 적용한 결과물을 만든다.
 리액트를 활용한 투자자산분석 관점 공유 sns의 형태를 생각중이다.</p>
<pre><code>    필요한 기능
    사진과 글을 업로드 삭제
    댓글과 좋아요, 공유, 저장 등 게시물을 활용한 기능 제공
    업로드 된 글을 보여주고 사용자 별 정렬할 수 있는 필터
    자신의 글과 공유 글을 보여주는 개인페이지
    베지어 곡선 애니메이션 효과</code></pre><h2 id="생각">생각</h2>
<p> 배운 것을 들어 아는 것과 그 것을 내 것으로 만드는 것은 다르다.
유저입장의 서비스와 경영자입장의 개발을 함께 그리고 나누어서 생각 해 본다.
이 고민은 과제의 난이도를 높이며 단순 프로젝트와는 다른 깊이의 배움을 준다. </p>
<p> DOM의 내용에 난해한 부분은 없었고, 로직도 단순했지만 
실제 서비스 되는 페이지의 기능을 동일하게 출력하는 것은 다른 차원이였다. 
html, css, js를 통해 사용자에게 제공되는 페이지라 생각을 하면 더 인터랙티브하고 
직관적으로 만들고 싶다.</p>
<p>자, 다시 키보드에 손을 올리자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[블록체인 : 스마트 컨트랙트 기초]]></title>
            <link>https://velog.io/@nft_sb/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EC%8A%A4%EB%A7%88%ED%8A%B8-%EC%BB%A8%ED%8A%B8%EB%9E%99%ED%8A%B8-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@nft_sb/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EC%8A%A4%EB%A7%88%ED%8A%B8-%EC%BB%A8%ED%8A%B8%EB%9E%99%ED%8A%B8-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Fri, 25 Nov 2022 06:16:55 GMT</pubDate>
            <description><![CDATA[<h1 id="핵심요약">핵심요약</h1>
<h3 id="스마트-컨트랙트의-장점">스마트 컨트랙트의 장점</h3>
<p>보안: 계약에 대한 중앙화된 공격 지점이 없고, 누군가에게 뇌물을 주고 계약 내용이나 결과를 변조할 위험이 없습니다.
신뢰성: 스마트 컨트랙트 로직이 조건에 부합해 계약이 이행되면 블록체인 네트워크에 있는 노드들에 의해 여러 번 수행되고 검증되기 때문에, 위변조가 매우 어렵고 정확성이 높습니다.
공평함: 계약 조건을 공유하고 강제하기 위해 분산화된 블록체인 네트워크를 사용하기 때문에, 수수료를 가져가는 등 영리적 목적의 중개자가 필요하지 않습니다.
효율성: 계약 이행을 자동화하기 때문에 계약 당사자들은 수동으로 데이터를 입력하거나, 상대방의 계약 의무 이행 여부 검증하거나, 중개자가 계약을 집행하는지 확인할 필요가 없습니다.</p>
<h3 id="utxo-동작원리">UTXO 동작원리</h3>
<h4 id="트랜잭션의-구조">트랜잭션의 구조</h4>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/7a11d9c6-7252-4865-a81c-db2bf7428742/image.png" alt=""></p>
<p>출력에는 자산이 잠겨있고, 입력으로 출력을 해제하여 출력에 있는 값을 꺼내, 새로운 출력에 자산을 담습니다. 트랜잭션에는 다른 곳에 잠겨있는 출력을 해제하는 입력과, 입력의 결과로 생긴 새로운 출력이 담기게 됩니다. 따라서 트랜잭션은 이전 출력을 해제하고, 새로운 출력을 만드는 추상적인 &quot;액션&quot;이라고 볼 수 있습니다. 이렇게 입력에 의해 생성된 후, 다른 입력에 의해 해제되지 않은 트랜잭션 출력을 UTXO라고 합니다.</p>
<h2 id="비트코인에서의-스마트-컨트랙트">비트코인에서의 스마트 컨트랙트</h2>
<p>비트코인에서는 스크립트(Script)라는 스크립터 언어를 사용해 스마트 컨트랙트를 구현합니다. 이 스크립트 실행을 통해 비트코인의 송금이 이루어집니다. 비트코인 스크립트는 일반적인 프로그래밍 언어와는 다르게 어떤 공식적인 문법이나 구문이 있는 것은 아닙니다. 대신 간단한 연산 목록으로 구성되어 있습니다.</p>
<p>이 스크립트 실행을 통해 비트코인의 송금이 이루어집니다. 이러한 특징으로 인해 비트코인은 프로그래밍할 수 있는 화폐(Programmable Money)에 대한 대중성을 부여했다고 볼 수 있습니다.</p>
<p>스크립트 동작원리</p>
<h3 id="스크립트는-역폴란드-표기법reverse-polish-notation으로-작성된-스택-기반-튜링-불완전-언어입니다">스크립트는 역폴란드 표기법(Reverse Polish Notation)으로 작성된 스택 기반 튜링 불완전 언어입니다.</h3>
<p>스크립트 프로그램은 두 종류의 객체를 가지고 있습니다.</p>
<pre><code>1. Opcode: 덧셈, 뺄셈, 곱셈과 같은 연산 작업을 나타냅니다.
2. 데이터: OP_CODE가 아닌 모든 데이터는 원시 데이터로 해석되며, 스택에 들어가게 됩니다.</code></pre><p>노드가 네트워크로부터 새로운 트랜잭션을 받으면, ScriptSig와 ScriptPubkey 필드를 추출하여 연결하여 최종적으로 <code>&lt;ScriptSig&gt;&lt;ScriptPubkey&gt;</code> 형태의 스크립트를 얻게 됩니다.</p>
<p>스크립트는 이 Opcode와 DATA를 일렬로 늘어놓은 것입니다. 여기서 포인터(Pointer)는 일렬로 늘어진 Opcode와 데이터를 순서대로 하나씩 가리킵니다. 만약 포인터가 데이터를 가리키면 데이터를 스택에 넣고, Opcode를 가리키면 스택에서 데이터를 꺼내옵니다. Opcode는 스택에서 데이터를 하나 이상 가져올 수 있지만, 중요한 것은 스택 구조이기 때문에 가장 나중에 들어온 데이터부터 가져온다는 것입니다.</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/90759d65-f666-43f8-bfdf-0cb142a26117/image.png" alt="">[스마트 컨트랙트&amp;핵심 요약-그림.2] 스크립트</p>
<h2 id="자주-쓰이는-비트코인-스크립트">자주 쓰이는 비트코인 스크립트</h2>
<h3 id="pay-to-pubkeyp2pk">Pay To PubKey(P2PK)</h3>
<p>두 개의 데이터와 하나의 opcode만 사용하는 가장 간단한 종류의 비트코인 스크립트입니다. P2PK는 퍼블릭 키에 직접 코인을 송금하는 데 사용합니다. 수신자의 공개 키를 직접 노출하기 때문에 보안에 취약하며, 오늘날에는 사용되지 않습니다.
<img src="https://velog.velcdn.com/images/nft_sb/post/4d1ee897-3224-46fa-b27b-bbd9582c82ee/image.png" alt="">[스마트 컨트랙트&amp;핵심 요약-그림.3] P2PK</p>
<h3 id="paytopubkeyhashp2pkh">PayToPubKeyHash(P2PKH)</h3>
<p>P2PKH는 P2PK 메커니즘과 거의 동일하며, 한 가지 차이점은 P2PKH에서는 ScriptPubkey가 공개 키의 해시값을 가지고 있다는 점입니다.
<img src="https://velog.velcdn.com/images/nft_sb/post/a7b924a4-b3c4-4b91-bfb6-51d01b0dd285/image.png" alt="">
P2PK와는 다르게, 서명과 공개키가 ScriptSig에 들어있습니다. ScriptPubkey는 P2PK에서와 다르게 여러 개의 Opcode를 가지고 있으며, 수신자의 공개키를 해싱한 값인 Hash 1 객체가 들어있습니다. 비트코인을 보내는 동안 송신자는 공개키의 해시값을 보내기 때문에 스크립트 이름의 PayToPubkeyHash인 것입니다.</p>
<h3 id="비트코인-스크립트가-스마트-컨트랙트인-이유">비트코인 스크립트가 스마트 컨트랙트인 이유</h3>
<p>UTXO는 일종의 계약으로 정의될 수 있으며, 이 계약은 유효한 해제 조건을 주면 잠긴 비트코인을 이동시킵니다. 오직 유효한 해제 조건을 줘야만 코인을 송금할 수 있는 계약인 것입니다. 이 계약의 실행은 비트코인 네트워크가 보장하기 때문에 계약 이행을 강제하기 위한 중개자가 필요하지 않습니다.</p>
<h2 id="이더리움에서의-스마트-컨트랙트">이더리움에서의 스마트 컨트랙트</h2>
<p>이더리움은 블록체인 기술을 활용해 스마트 컨트랙트와 암호화폐 거래를 제삼자 없이 안전하게 이뤄질 수 있도록 하는 오픈소스 퍼블릭 서비스입니다. 누구든지 분산형 어플리케이션(dApp)을 이더리움 네트워크에 배포할 수 있습니다. 이더리움은 개발자들이 dApp을 만들 수 있도록 튜링 완전한 언어인 솔리디티(Solidity)를 제공하였으며, 이더리움 네트워크에 올라간 솔리디티 코드는 EVM(Ethereum Virtual Machine)을 통해 실행됩니다.</p>
<h3 id="비트코인과-이더리움의-차이점">비트코인과 이더리움의 차이점</h3>
<p>비트코인은 암호화폐를 거래하는 반면, 이더리움은 스마트 컨트랙트를 활용한 분산 어플리케이션(dApp)을 만들 수 있도록 솔리디티 언어와 EVM(Ethereum Virtual Machine)을 지원합니다.
비트코인은 무허가 퍼블릭 트랜잭션만을 허용하지만, 이더리움은 허가 트랜잭션과 무허가 트랜잭션을 모두 허용합니다.
비트코인에서는 플랫폼을 실행하고 트랜잭션을 검증하는 채굴 노드가 보상받습니다. 기본적으로 새로운 블록을 만드는 첫 번째 컴퓨터가 비트코인을 보상으로 받습니다. 반면, 이더리움은 블록 생성에 대한 보상을 제공하지 않으며, 대신 채굴 노드가 트랜잭션 수수료를 받을 수 있도록 합니다.</p>
<h2 id="evm">EVM</h2>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/e21297d6-223a-4bd6-b9af-1ab4bbb14a02/image.png" alt="">[스마트 컨트랙트&amp;핵심 요약-그림.5] EVM 계층</p>
<p>EVM(Ethereum Virtual Machine)은 우리가 짠 코드와 이더리움 블록체인 사이에 있는 가상 머신으로, 블록체인에서 코드가 실행될 수 있도록 합니다.</p>
<p>EVM은 솔리디티를 읽을 수 없기 때문에, 먼저 우리가 작성한 솔리디티 코드를 solc를 이용해 컴파일하여 EVM이 읽을 수 있는 바이트코드 형태로 만듭니다. 그리고 이 바이트코드를 Geth를 이용해 이더리움 네트워크에 올립니다. EVM에서는 바이트코드를 Opcode로 변환하여 실행합니다.
<img src="https://velog.velcdn.com/images/nft_sb/post/b091e89e-99f9-45a0-ba16-c07e2bfd263c/image.png" alt=""></p>
<h2 id="솔리디티">솔리디티</h2>
<p>솔리디티는 스마트 컨트랙트를 실행하는 객체 지향(Object-Oriented), 정적 타입(Static Typed), 고급(High-Level) 스크립트 언어로, EVM에서 실행됩니다.</p>
<h3 id="솔리디티는-튜링-완전-언어이다">솔리디티는 튜링 완전 언어이다</h3>
<p>튜링 머신은 실제로 구현된 기계가 아니라, 이론상으로 존재하는 기계로, 오늘날 우리가 구축할 수 있는 가장 강력한 기계 컴퓨터를 설명할 때 사용하는 수학적 연산 모델입니다.</p>
<p>어떤 프로그래밍 언어나 추상 기계가 튜링 머신과 동일한 연산 능력을 갖출 때, 우리는 그것이 튜링 완전(Turing-Complete)하다고 말합니다. 반대로 튜링 머신보다 연산 능력이 떨어질 경우 튜링 불완전(Turing-Incomplete)하다고 합니다.</p>
<h3 id="스마트-컨트랙트와-튜링-완전-불완전성">스마트 컨트랙트와 튜링 완전, 불완전성</h3>
<p>사토시 나카모토는 무한 반복 공격과 같은 보안상의 이슈를 고려해 의도적으로 반복문 Opcode를 제외했습니다. 따라서 비트코인 스크립트를 두고 튜링 불완전하다고 말합니다.</p>
<p>비트코인으로 스마트 컨트랙트를 구현할 때는 반복문을 사용할 수 없다 보니, 단순한 스마트 컨트랙트를 만드는 데에 그칠 수밖에 없었습니다. 이더리움의 핵심은 이러한 비트코인의 튜링불완전성이라는 한계를 넘어, 개발자가 원하는 스마트 컨트랙트를 유연하게 구현할 수 있도록 튜링 완전을 제공하는 것입니다. EVM은 반복문 Opcode들을 지원하는 대표적인 튜링 완전 머신이며, 솔리디티는 튜링 완전 머신을 동작하게 하는 튜링 완전 언어입니다.</p>
<h3 id="솔리디티-개발-도구">솔리디티 개발 도구</h3>
<p>Remix IDE
solc
Ganache
TestNet
Truffle, Embark, Dapple</p>
<h2 id="스마트-컨트랙트-동작-원리">스마트 컨트랙트 동작 원리</h2>
<h3 id="이더리움-상태-머신">이더리움 상태 머신</h3>
<p>이더리움은 거래에 기반을 둔 상태 머신(Transaction-based state machine)입니다. 상태 머신이란 일련의 입력을 읽고, 그 입력을 기반으로 새로운 상태로 전환하는 것을 의미합니다. 이더리움의 상태에는 수천 개의 트랜잭션이 있습니다. 이 트랜잭션은 블록이라는 그룹에 묶여 있으며, 블록은 직전에 만들어진 블록과 이어져 있습니다.
<img src="https://velog.velcdn.com/images/nft_sb/post/66e772e6-399a-4bf3-9041-7a3384b58347/image.png" alt="">[스마트 컨트랙트&amp;핵심 요약-그림.7] 이더리움의 트랜잭션 블록</p>
<h3 id="eos와-ca">EOS와 CA</h3>
<p>이더리움에는 EOS(External Owned Account)와 CA(Contract Account)라는 두 종류의 계정이 있습니다. 모든 계정은 주소로 식별되며, 동일한 주소 공간을 가집니다.</p>
<p>EOS와 CA 모두 잔액(Balance), 논스(Nonce), 스토리지(Stroage), 컨트랙트 코드(Contract Code)로 구성되어 있습니다.</p>
<pre><code>Balance: 계정의 현재 이더 잔고
Nonce: EOA의 경우, 해당 EOA로부터 보내진 트랜잭션의 숫자. CA의 경우,
        해당 CA로부터 생성된 컨트랙트의 숫자를 의미합니다.
StorageRoot: 머클 패트리샤 트리의 루트 노드를 해싱한 값.
Contract Code: EVM이 실행할 코드의 해싱된 값. EOA에는 코드를 저장할 수 없기 때문에 비어있습니다.</code></pre><p>CA는 스스로 새로운 트랜잭션을 만들 수 없습니다. CA는 EOS나 다른 CA에서 받은 트랜잭션에 대한 응답에 대해서만 트랜잭션을 만들 수 있습니다.</p>
<h3 id="전역-상태">전역 상태</h3>
<p>이더리움의 전역 상태는 계정 주소와 계정 상태를 매핑한 것으로 구성되어 있습니다. 이 매핑은 머클 패트리샤 트리(Merkle Patricia Tree) 형태로 저장되어 있습니다.</p>
<p>머클 패트리샤 트리에서 변조가 시도되면 그 즉시 발견되기 때문에, 루트 노드는 데이터에 대한 ID처럼 사용될 수 있습니다. 또한 블록 헤더는 상태, 트랜잭션, 영수증 트리의 루트 노드 값을 가지고 있기 때문에, 네트워크의 노드들은 모든 상태를 저장하고 있지 않더라도 이더리움의 상태 일부분을 검증할 수 있습니다.</p>
<h3 id="트랜잭션과-메시지">트랜잭션과 메시지</h3>
<p>트랜잭션은 메시지 호출(Message Call)과 컨트랙트 생성(Contract Creations) 두 종류로 나뉩니다.</p>
<p>이더리움의 모든 트랜잭션은 항상 EOA에서 만들어지고 블록체인에 올라갑니다. 즉, 트랜잭션은 외부 세계를 이더리움 내부의 상태로 연결해주는 다리와 같습니다. 연결의 창구가 CA입니다.</p>
<h3 id="ca-생성">CA 생성</h3>
<p>논스를 0으로 설정한다.
송신자가 CA 생성 트랜잭션에 이더를 함께 보낸 경우, 이를 CA의 잔금(Balance)으로 설정한다.
잔금에서 value 만큼을 제외한다.
CA의 스토리지를 빈 값으로 초기화한다.
CA의 코드를 빈 문자열의 해시값으로 초기화한다.
계약을 초기화하는 이 init 코드를 실행할 때는 가스를 사용합니다. 트랜잭션은 남아있는 가스보다 더 많은 가스를 소비할 수 없기 때문에, 만약 남아있는 가스를 다 사용한 경우 OOG(Out-of-Gas) 예외 처리와 함께 코드 실행이 종료됩니다. OOG로 인한 트랜잭션 종료가 발생하면 상태는 트랜잭션 실행 이전 상태로 돌아갑니다.</p>
<h2 id="트랜잭션-실행-모델과-evm">트랜잭션 실행 모델과 EVM</h2>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/72ec37cc-68dc-4d7a-b51c-a53c2e7ffeb7/image.png" alt="">
<img src="https://velog.velcdn.com/images/nft_sb/post/1f447a3c-e276-4f8c-b4f7-03b81a9495bd/image.png" alt="">
[스마트 컨트랙트&amp;핵심 요약-그림8, 9] EVM의 구성 요소, EVM 실행 모델</p>
<h2 id="스마트-컨트랙트-실행-비용">스마트 컨트랙트 실행 비용</h2>
<p>이더리움에서 가장 중요한 개념 중 하나는 트랜잭션 실행 수수료입니다. 이더리움에서 트랜잭션의 결과로 발생하는 모든 연산은 수수료를 요구합니다. 이 수수료를 가스(Gas)라고 합니다.</p>
<p>가스는 트랜잭션 코드에 있는 모든 Opcode를 실행하는데 필요한 수수료를 측정하는 데 사용하는 단위입니다. Gas Price는 가스당 지불하려고 하는 이더의 양을 의미하며, Gwei라는 단위를 사용합니다.</p>
<p>트랜잭션 송신자는 Gas Limit과 Gas Price를 트랜잭션에 지정합니다. 이 Gas Price와 Gas Limit은 송신자가 트랜잭션을 실행하는데 지불하고자 하는 Wei의 최대 양을 의미합니다.</p>
<p>채굴자는 연산을 수행하고 트랜잭션을 검증하는 데에 자원을 소모하기 때문에 이에 대한 보상으로 가스 수수료를 받습니다.</p>
<h3 id="수수료를-지불하는-이유">수수료를 지불하는 이유</h3>
<p>이더리움은 튜링 완전 언어이기 때문에, 튜링 불완전한 비트코인 스크립트와는 달리 반복문을 지원합니다. 그러나 반복문의 가장 큰 단점은 무한 루프 문제가 일어날 수 있다는 것입니다. 만약 악의적인 사용자가 큰 자원을 소모하는 무한 루프 코드가 들어있는 트랜잭션을 실행시킨다면, 트랜잭션은 이더리움 네트워크의 엄청난 양의 자원을 소모하게 될 것이고, 심각하게는 이더리움 네트워크 전체가 멈출 수도 있습니다.</p>
<p>수수료는 이러한 악의적인 공격으로부터 네트워크를 보호합니다. 연산마다 수수료를 부과하면 악의적인 사용자라도 수수료를 지불해야 하므로 쉽게 무한 루프 코드를 실행시킬 수 없습니다. 또한 의도치 않게 무한 루프를 만든 코드를 실행시키더라도 Gas Limit을 설정해두면 지정해둔 가스를 다 소모하기 전에 실행을 멈출 수 있습니다.</p>
<h2 id="프라이빗-블록체인에서의-스마트-컨트랙트">프라이빗 블록체인에서의 스마트 컨트랙트</h2>
<p>프라이빗 블록체인은 네트워크 내에서 초대된 사용자만이 네트워크에 참여하고, 원장에 접근할 수 있는 허가형(Permissioned) 블록체인을 의미합니다. 프라이빗 블록체인은 채굴 과정과 합의 알고리즘에 대한 권한을 중앙 기관이 개발하고 유지합니다. 중앙 기관은 네트워크에 참여할 수 있는 사용자를 결정합니다.</p>
<h3 id="프라이빗-블록체인의-특징">프라이빗 블록체인의 특징</h3>
<pre><code>높은 효율성
완전한 개인 정보 보안
불법적 활동 제한</code></pre><h3 id="대표적인-프라이빗-블록체인">대표적인 프라이빗 블록체인</h3>
<p>하이퍼레저
R3
넥스레저</p>
<h3 id="하이퍼레저-패브릭과-체인코드">하이퍼레저 패브릭과 체인코드</h3>
<p>하이퍼레저 패브릭의 블록체인적 특징
프라이버시와 기밀성: 패브릭의 채널(Channel)은 네트워크의 특정 하위 노드 집합에게 트랜잭션 프라이버시와 기밀성을 보장해줍니다.
효율적인 처리: 네트워크의 동시성과 병렬성을 제공하여, 트랜잭션 실행을 트랜잭션 정렬 및 커밋과 분리합니다.
체인코드 기능: 이더리움의 스마트 컨트랙트에 해당하는 체인코드를 제공합니다.
모듈식 설계: 아키텍쳐들을 모듈식으로 구현하여 필요한 모듈들을 가져다 쓸 수 있도록 선택권을 제공합니다.</p>
<h3 id="하이퍼레저-패브릭의-주요-개념">하이퍼레저 패브릭의 주요 개념</h3>
<p>피어(Peer) 피어는 블록체인 네트워크의 기본 요소이며, 원장과 스마트 컨트랙트를 호스팅하는 노드입니다. 네트워크와의 상호작용의 시작점이며, 어플리케이션이 체인코드(스마트 컨트랙트)를 실행하여 쿼리를 하거나 원장을 업데이트하도록 합니다.
커밋 피어와 보증 피어로 나뉩니다.
채널(Channel) 하이퍼레저 패브릭 채널은 둘 이상의 특정 네트워크 노드 간의 통신을 위한 프라이빗 서브넷으로, 프라이빗 트랜잭션을 수행하기 위한 목적으로 사용됩니다.</p>
<h3 id="스마트-컨트랙트와-체인-코드">스마트 컨트랙트와 체인 코드</h3>
<p>스마트 컨트랙트는 트랜잭션을 관리하며, 체인 코드는 스마트 컨트랙트를 배포하기 위해 패키징하여 관리합니다.</p>
<h2 id="이더리움과-하이퍼레저-패브릭의-차이점">이더리움과 하이퍼레저 패브릭의 차이점</h2>
<p>플랫폼의 목적: 이더리움은 EVM 위에서 스마트 컨트랙트를 실행하는 하나의 목적을 위해 만들어졌습니다. 하이퍼레저는 고성능과 신뢰성이 높은 블록체인 개발을 위한 산업 전반의 협업을 가속화하기 위해 도입되었습니다.
작동 방식: 이더리움은 퍼블릭 블록체인으로, 누구나 블록체인 네트워크에 접근할 수 있고, 네트워크에 접근할 때 허가받을 필요가 없습니다. 반면, 하이퍼레저 패브릭은 프라이빗 블록체인으로, 허가된 사용자만이 네트워크에 참여할 수 있습니다.
피어 역할: 이더리움은 트랜잭션이 완료되면 이를 위해 여러 노드가 참여해야 하므로 확장성, 프라이버시, 효율성 등의 문제가 발생할 수 있습니다. 하이퍼레저는 네트워크 내의 각 피어에게 트랜잭션을 수행하기 위해 정보를 제공할 필요가 없는 DLT(Distributed Ledger Technology)를 제공합니다.
기밀성: 이더리움은 퍼블릭 네트워크이기 때문에, 블록체인 네트워크에 기록된 모든 트랜잭션에 누구든지 접근할 수 있습니다. 하이퍼레저는 허가형 프라이빗 네트워크이기 때문에 허가된 멤버만 트랜잭션에 접근할 수 있습니다.
합의 메커니즘: 이더리움은 모든 노드가 합의에 도달해야 하는 PoW 합의 알고리즘을 사용합니다. 반면, 하이퍼레저 패브릭은 다른 종류의 합의 알고리즘을 사용합니다. 하이퍼레저 패브릭에서는 아예 합의하지 않거나, 다양한 합의 프로토콜 중 하나를 선택할 수 있습니다.
프로그래밍 언어: 이더리움은 이더리움의 자체 언어인 솔리디티를 사용하지만, 하이퍼레저에서는 Go 언어를 사용합니다.</p>
<h2 id="스마트-컨트랙트를-활용한-새로운-서비스들">스마트 컨트랙트를 활용한 새로운 서비스들</h2>
<p>금융 상품(DeFi)
게임 및 NFT
DAO
ICO
브릿지</p>
<h3 id="스마트-컨트랙트-활용-사례">스마트 컨트랙트 활용 사례</h3>
<p>일정한 형식의 반복적인 계약이 많은 경우
사례: 보험
원격자 간 계약 체결이 필요한 경우
사례: 자동차 렌탈 서비스
제품의 유통 추적이 필요한 경우
사례: 물류 유통</p>
<h2 id="오라클-문제">오라클 문제</h2>
<h3 id="오라클">오라클</h3>
<p>오라클은 web API나 마켓 데이터 피드와 같은 방식을 통해 블록체인과 스마트 컨트랙트용 외부 데이터를 검색하고 검증하는 것을 의미합니다.</p>
<h3 id="오라클-문제-1">오라클 문제</h3>
<p>오라클 문제는 서드 파티 오라클과 스마트 컨트랙트의 무신뢰성 실행 간 보안, 인증, 신뢰 충돌 문제에 관한 것입니다. 스마트 컨트랙트는 주어진 데이터에 따라 계약 이행 여부를 결정할 뿐이지, 데이터에 대한 자체적인 판단 능력은 갖추고 있지 않습니다.</p>
<h2 id="컴퓨터에서의-난수-생성">컴퓨터에서의 난수 생성</h2>
<p>컴퓨터는 입력받은 값에 대해 정해진 행동을 하므로, 조종할 수 없는 새로운 데이터를 생성하는 것을 잘하지 못합니다. 따라서 컴퓨터 과학에서 난수는 유사 난수(Pseudo Random)와 진짜 난수(True Random)로 나뉩니다. 유사 난수는 컴퓨터에 있는 데이터와 알고리즘을 통해 얻게 되는 난수입니다. 이 난수는 컴퓨터 내부에 있는 알고리즘과 데이터를 가지고 생성되었기 때문에 특정한 패턴을 가지게 되고, 이에 따라 예측할 수 있습니다.</p>
<h3 id="블록체인에서의-난수-생성-문제">블록체인에서의 난수 생성 문제</h3>
<p>블록체인에서는 모든 노드가 트랜잭션을 검증함으로써 데이터의 무결성을 보장하기 때문에, 블록체인에서 일어나는 모든 동작은 결정적인 방식으로 일어납니다.</p>
<p>예를 들어, 이더리움 스마트 컨트랙트에는 랜덤 함수가 구현되어 있지 않습니다. 노드들이 블록을 검증하기 위해서는 블록에 있는 트랜잭션을 실행한 결과 상태 값과 현재 자신이 가지고 있는 상태 값을 비교해야 합니다. 그런데 트랜잭션에서 무작위 값이 나오면 트랜잭션을 실행한 결과 상태 값이 매번 변할 것이기 때문에 데이터의 무결성을 증명하기가 매우 어려워집니다.</p>
<p>그러나 우리가 원하는 난수 생성은 결정적이면 안 됩니다. 매번 예측할 수 없는 값이 나와야 예측하거나 조작할 수 없기 때문입니다.</p>
<h3 id="블록체인-난수를-생성하는-방법">블록체인 난수를 생성하는 방법</h3>
<p>Commit Reveal Scheme
BLS Scheme</p>
<h2 id="question">Question</h2>
<h3 id="1-비트코인은-왜-튜링-불완전성인가요">1. 비트코인은 왜 튜링 불완전성인가요?</h3>
<pre><code>비트코인 스크립트는 보안상의 이유로 Opcode를 사용할 수 없게 설계되어있다.
때문에 비트코인에서는 반복문을 사용할 수 없다보니 단순한 스마트 컨트랙트를 만드는데 그쳤다.</code></pre><h3 id="2-스마트-컨트랙트가-포함된-이더리움은-왜-튜링-완전인가요">2. 스마트 컨트랙트가 포함된 이더리움은 왜 튜링 완전인가요?</h3>
<pre><code>반대로 이더리움은 dApp을 만들 수 있도록 튜링 완전한 언어인 솔리디티를 제공하면서 개발자가 원하는 스마트 
컨트렉트를 유연하게 구현할 수 있게 되었다.</code></pre><h3 id="3-하이퍼레저-패브릭에서-사용되는-체인링크와-이더리움에서-사용되는-솔리디티의-차이점은-무엇인가요">3. 하이퍼레저 패브릭에서 사용되는 체인링크와 이더리움에서 사용되는 솔리디티의 차이점은 무엇인가요?</h3>
<pre><code>플랫폼 목적 : 이더리움은 evm위에서 스마트 컨트랙트를 실행하기위해 
            만들어졌고 하이퍼레저는 고성능과 신뢰성을 바탕으로 산업 전반의 
            협업을 가속하기위해 도입되었다.


작동 방식 : 이더리움은 허가없이 누구나 블록체인 네트워크에 접근할 수
            있는 반면 하이퍼레저 패브릭은 허가된 사용자만 네트워크에 
            참여할 수 있다.


피어 역할 : 이더리움은 피어마다 역할이 있는 반면, 하이퍼레저는 각 피어에게 정보를 
            제공할 필요가 없는 DLT를 제공한다.


합의 메커니즘 : 이더리움은 모든 노드가 합의에 도달해야하는 POS합의 알고리즘을 사용하고 
            하이퍼레저 패브릭에서는 아예 합의하지 않거나 다양한 합의 프로토콜 중 
            하나를 선택할 수 있다.


프로그래밍 언어 : 이더리움은 이더리움의 자체 언어인 솔리디티를 사용하지만, 
                하이퍼레저에서는 GO언어를 사용합니다. </code></pre><h3 id="4-evm은-무엇인가요-eos-vm은-무엇인가요-두-개의-차이점은-무엇인가요-왜-jvm으로-만들어졌나요">4. EVM은 무엇인가요? EOS VM은 무엇인가요? 두 개의 차이점은 무엇인가요? 왜 JVM으로 만들어졌나요?</h3>
<pre><code>VM: Virtual Machine 가상머신

EVM: 이더리움, EOS VM: 이오스에서 사용하는 VM

    개발자가 작성한 코드를 이더리움 블록체인에서 실행될 수 있도록 하는 가상 머신

    개발자가 솔리디티로 작성 =&gt; 바이트코드로 변환(solc로 컴파일) =&gt; EVM이 Opcode단위로 읽음</code></pre><h3 id="5-banchor-알고리즘이-무엇인가요-왜-뱅코르-알고리즘이-있는데-유니스왑을-사용하나요">5. Banchor 알고리즘이 무엇인가요? 왜 뱅코르 알고리즘이 있는데 유니스왑을 사용하나요?</h3>
<pre><code>뱅코르 알고리즘은 스마트 컨드랙트 위에서 코인을 거래하는 것이다.

유니스왑을 사용하는 이유는 
    1. 단순하고  2. 더 빠르고  3. 비용이 적기 때문이다. 
        =&gt; 이로 인해 더 많은 유동성 발생

유니스왑의 경우 스마트 컨트랙트로 작동을 하지만 
    1. 뱅커와 다르게 자체 토큰이 존재하지 않고  
    2. 단순한 알고리즘을 사용하게 된다.  
        =&gt; 때문에 비용이 저렴</code></pre><h3 id="6-이더리움의-solidity-언어와-다르게-go-c을-사용하면-비결정적-문제가-생깁니다-무슨-의미인가요">6. 이더리움의 Solidity 언어와 다르게, Go, C++을 사용하면 비결정적 문제가 생깁니다. 무슨 의미인가요?</h3>
<pre><code>동일한 입력값을 넣는다 하더라도, 매번 다른 과정을 거쳐 다른 결과를 도출하는 것을 
비결정적 문제라 합니다. 이에 반해, 솔리디티의 경우 튜링 완전성을 가지고 있고, 
모든 노드에서 나온 결과값이 동일하기에 결정적 특성을 가지고 있습니다.</code></pre><h3 id="7-이더리움의-solidity-언어는-어떤-식으로-리소스에-대해-과금을-하나요">7. 이더리움의 Solidity 언어는 어떤 식으로 리소스에 대해 과금을 하나요?</h3>
<pre><code>트랜잭션이 발생하는 모든 연산에 있어 수수료를 지불하는 방식으로 과금을 구합니다. 
이에 따라 연산이 복잡할 경우 채굴자는 더 높은 수수료를 요구합니다. 또한 송신자가 
자신의 트랜잭션을 먼저 실행시킬 수 있도록 채굴자에게 수수료를 제공합니다.
 1) 채굴자에게 주는 수수료
 2) 트랜잭션에 드는 연산에 대한 수수료</code></pre><h3 id="8-solidity-처럼-c이나-go로-만든-프로그램에서-cpu-memory-storage-를-사용한-만큼의-지표를-구하고-싶을-때-어떻게-할-수-있을까요">8. Solidity 처럼 C++이나 Go로 만든 프로그램에서 CPU, Memory, Storage 를 사용한 만큼의 지표를 구하고 싶을 때 어떻게 할 수 있을까요?</h3>
<pre><code>가상 메모리 상태와 레지던트 세트 크기로 CPU, Memory, Storage 사용량을 구할 수 있다.
런타임에 가상메모리 사용량, 레지던트 세트 크기 등과 같은 메모리 사용량을 얻을 수 있다. 
(일부 시스템 라이브러리를 사용할 수 있음)
C++의 경우 &quot;/proc/self/stat&quot; 폴더에서 모든 세부 정보를 얻을 수 있다.</code></pre><h3 id="9-이더리움-스마트-컨트랙트에서는-왜-타이머나-이벤트를-사용할-수-없나요">9. 이더리움 스마트 컨트랙트에서는 왜 타이머나 이벤트를 사용할 수 없나요?</h3>
<pre><code>다른 프로그래밍 언어로 작성된 프로그램과 달리 스마트 계약 코드는 타이머나 이벤트(event)
등을 통해서 실행되지 못한다. 예를 들어, 특정 시간에 특정 주소로 자동으로 송금하는 프로세스 
등은 구현할 수 없다. 왜냐하면 스마트 컨트랙트는 자기 자신의 개인키(private key)가 없기
때문에 스스로 어떤 트랜잭션도 발생시킬 수 없기 때문이다.</code></pre><h3 id="10-여러-계약이-엮인-파일을-배포하려고-하면-무슨-일이-발생하나요">10. 여러 계약이 엮인 파일을 배포하려고 하면 무슨 일이 발생하나요?</h3>
<pre><code>단일 마이그레이션 파일에서 둘 이상의 스마트 계약을 배포할 수 있다. Truffle 마이그레이션은 
계약, 라이브러리, 인수 전달을 연결하기 위해 정확히 이루어진다.계약이 상호 작용할 필요가 없는 
경우 각각에 대해 서로 다른 마이그레이션 파일을 갖는 것이 유용하다. 그중 하나만 변경한 경우 
변경되지 않은 코드를 재배포하지 않고 특정 마이그레이션을 개별적으로 실행할 수 있다. </code></pre><h3 id="11-노드는-어떻게-스마트-컨트랙트-코드를-실행하나요">11. 노드는 어떻게 스마트 컨트랙트 코드를 실행하나요?</h3>
<pre><code>if or when (이벤트 x가 실행되면) {  // 조건
    액션 y를 실행하라  // 계약 이행
    }

    코드가 블록체인 네트워크에 올라가면, 네트워크는 미리 결정된 조건이 충족되고, 
    검증된 경우 조건에 따른 액션을 실행 
    코드에 따라 계약이 실행 됨을 보장하는 결정론적인 상태(Deterministic State)인 
    다자간 디지털 계약이 바로 스마트 컨트랙트이다.</code></pre><h3 id="12-dapp이란-무엇이고-일반적인-어플리케이션과는-무엇이-다른가요">12. dApp이란 무엇이고 일반적인 어플리케이션과는 무엇이 다른가요?</h3>
<pre><code>일반적인 어플리케이션: 중앙서버
디앱: 탈중앙화됨. 블록체인 생태계에 직접적으로 블록으로 저장됨
장점: 보안성 및 투명성, 인센티브, 거버넌스 참여
단점: 느린 속도, 높은 비용</code></pre><h3 id="13-evm-메모리의-구성-요소가-어떻게-되나요">13. EVM 메모리의 구성 요소가 어떻게 되나요?</h3>
<pre><code>1) 스택: EVM은 들어오는 바이트코드를 스택구조로 처리함
2) 메모리: 휘발성. 들어오는 데이터를 배열로 저장하고 
            프로그램이 종료되면 메모리에 있는 데이터도 사라짐
3) 스토리지: 비휘발성, 시스템 상태에 따라서 유지. 
            가상 ROM이라는 공간에 코드와 별개로 분리해서 저장</code></pre><h3 id="14-스마트-컨트랙트의-실행-비용이-지정된-가스보다-더-많이-소요된다면-무슨-일이-일어나나요">14. 스마트 컨트랙트의 실행 비용이 지정된 가스보다 더 많이 소요된다면 무슨 일이 일어나나요?</h3>
<pre><code>사용자의 경우 
트랜잭션을 실행하기 전 가스한도를 설정해둔다(지정된 가스). 
지정된 가스보다 스마트 컨트랙트 실행비용이 높은 경우, 
즉 한도를 낮게 설정한 경우 트랜잭션 연산을 
완벽히 마치지 못하게 되고 트랜잭션을 실패한다. 
또한 그 시점까지 사용된 수수료는 환불받지 못한다. 
이에 따라 스마트 컨트랙트 실행비용에 대한 추측이 필요하며, 
추측값보다 한도를 높이 설정해둔다면 트랜잭션을 마치더라도 
남는 이더는 환불 받을 수 있을 것이다.</code></pre><h3 id="15-트랜잭션에서-가스-사용량은-무엇에-따라-달라지며-트랜잭션-수수료는-어떻게-계산되나요">15. 트랜잭션에서 가스 사용량은 무엇에 따라 달라지며, 트랜잭션 수수료는 어떻게 계산되나요?</h3>
<pre><code>가스 사용량은 트랜잭션을 처리할 때 드는 비용이다.
이더리움은 공격자들의 공격을 방지하기 위해 트랜잭션 처리하는 데에 수수료를 부과한다.
수수료 계산 원리 : 트랜잭션 크기에 따라 결정 
(클수록 많은 수수료 소요, 작을수록 적은 수수료 소요)

0.000000001ETH = 1 Gwei(10억 Gwei  = 1 ETH) 
가스비는 이더리움 채굴자들이 채굴에 대한 보상으로 가져감</code></pre><h2 id="이론을-학습하며">이론을 학습하며...</h2>
<pre><code>4명의 페어분과 함께 학습하며 이론을 적립했다.
게더에서 진행 한 첫 페어였는데, 게임 하듯 학습을 한 것 같다.
기다리던 스마트 컨트랙트를 드디어 다루게 된 것 같아서 기쁨이 과했지.
관련 책 몇 권 봤다고 익숙할 줄 알았는데, 내가 쓸 수 있도록 익힌다는 것은 전혀 다른 문제인듯. 
8번과 10번의 경우 한글 써치에 한계를 느꼈는데, 역시 구글링은 영어로.
Crypto Zombies로 게임을 빙자한 솔리디티 코플릿을 풀어야한다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Responsive Web]]></title>
            <link>https://velog.io/@nft_sb/Responsive-Web</link>
            <guid>https://velog.io/@nft_sb/Responsive-Web</guid>
            <pubDate>Sat, 19 Nov 2022 15:06:51 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nft_sb/post/a1e786aa-5bd0-4335-90f4-3e84d1c24848/image.gif" alt=""></p>
<p><a href="https://github.com/Russ481-k/mini_Projects">반응형 웹 깃허브</a></p>
<h1 id="재미있는-것을-해야-하는-법이다">재미있는 것을 해야 하는 법이다.</h1>
<p>다른 IT교육과정들을 살펴 보니 비전공자도 실무를 잡으려면 프론트앤드건 백앤드건 6개월을 잡는다. BEB에서 2개월만에 1년을 파야하는 범위를 지나가버렸다. 지나간 과정에도 코드한 줄 기억나지 않는다는 자괴감에서 살아남기 위해서 필요한 것은 흥미 위주의 프로젝트이다. 지난 교육에서 배웠던 내용들을 모두 사용할 수 있는 프로젝트로 내가 가장 재미있게 만들 수 있는 방법으로 진행 해 본다.</p>
<h3 id="목표">목표</h3>
<p> Crypto Derivatives Market에서 API로 
        Bitcoin Future &amp; Option의 데이터를 받아 실시간 스프레드 분석하여 
        상품별 Market Timing 평가 
        =&gt; 실시간 유효한 상품과 행사가를 출력하는 웹앱 제작 </p>
<h3 id="디자인-위주로-시작-htmlcssjs">디자인 위주로 시작 HTML/CSS/JS</h3>
<p> 비루한 실력이라도 흥미있는 것 부터 한다. 재미없으면 안 한다.</p>
<h3 id="원하는-퀄리티의-웹앱-나올-때-까지-리팩토링">원하는 퀄리티의 웹앱 나올 때 까지 리팩토링</h3>
<p>VBA로 Vertual Derivatives Market 완성했던 순간을 기억하자. 
닿을 때 까지 만들다 보면 어떻게든 만들어지고, 나는 성장한다.</p>
<h3 id="tradingview-api를-통해-실전에-사용되는-데이터를-다루는-웹앱-운영">tradingView API를 통해 실전에 사용되는 데이터를 다루는 웹앱 운영</h3>
<p>여기까지 도달할 수 있으면 2단계. 여기에 AI 솔루션 연동시키면 3단계 도달로 준비 해 두었던 프로젝트 완료다. 트레이딩 분석에 적합한 AI모델 찾을 때가 더 쉬웠던 것 같다. 흥미없지만 필요한 기능을 내 것으로 만드는 게 어렵다. 먼 길 돌아간다. 그렇게 언젠가는 닿는다.  </p>
<h1 id="반응형-웹">반응형 웹</h1>
<p>미디어 쿼리로 width크기에 따라 각 영역이 바람직한 비율로 구성되도록 했다.
시행착오 겪으면서 CSS가 익숙해 졌다. 역시 만들어 봐야 그 맛을 알지.
루트 설정으로 수정에 용이하게 초기설정 하는 것, 호버, 포지션 앱솔루트, 디스플레이 플렉스, 클램프, 트렌잭션 트렌스폼, 트렌스폼 로테이트, 비디오, 플렉스 비율 등을 살펴 보았다.</p>
<h2 id="반응형-웹-1">반응형 웹</h2>
<p>반응형 웹은 다양한 디바이스와 다양한 크기의 화면에서 일관되게 잘 작동하는 웹 페이지를 제작하는 일이다. </p>
<h3 id="주요-내용">주요 내용</h3>
<ol>
<li><p>소비자가 어떤 디바이스를 이용하든 시각적으로 아름답고 기능적이며 사용성이 높다.</p>
</li>
<li><p>사용자는 하루에도 몇 번씩 다양한 디바이스를 오간다.
다양한 디바이스에서 사이트에 접속했을 때 사이트가 느려지거나 둘러보기 어렵거나 시각적으로 아름답지 않으면 소비자는 금세 관심을 잃어버린다.</p>
</li>
<li><p>각 구성 요소의 차원에서 반응형 디자인과 기능을 고민해야 하고, 반응성을 높일 수 있는 디자인 프로세스와 시스템이 필요하다.</p>
</li>
</ol>
<p>반응형 웹 사이트는 고객 경험을 최적화하고 사이트 성능을 높이는 기회가 된다. 사이트의 반응성이 증가하면, 이탈률이 감소한다. 그리고 다양한 뷰포인트와 다양한 고객의 사용 패턴에 맞게 최적화할 수 있어 고객 참여 증가한다.</p>
<h3 id="반응형-웹의-이점">반응형 웹의 이점</h3>
<p>반응형 웹디자인은 고객에게도 혜택을 준다. 브랜드가 고객의 디바이스와 니즈를 고려하기 때문. 예를 들어 직장에서 데스크탑 컴퓨터로 풍부한 인터랙티브 경험을 즐기고, 이후 모바일 디바이스로 빠른 페이지 로드와 작은 화면에 최적화된 터치 인터페이스를 경험한다.</p>
<p>출처 : <a href="https://business.adobe.com/kr/glossary/responsive-web-design.html">반응형 웹</a></p>
<h2 id="실습내용">실습내용</h2>
<p>이틀 간 페이지 만들며,
다음과 같은 내용이 기억에 남는다.</p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/c68b44d5-1121-49a5-b13d-2fe64282ac7e/image.jpg" alt=""></p>
<h3 id="root">root</h3>
<p>루트를 상위에 설정하여 전체적인 디자인 수정에 용이하게 설정할 수 있다.
반복적으로 설정해야하는 요소들이 있는데 루트를 설정하고 var()를 통해 지정한 내용을 사용할 수 있다. 같은 요소들로 설정 해 놓고 그 요소들을 한 번에 수정할 수 있다는 장점이 있다. </p>
<pre><code class="language-css">:root {
    /* Color */
    --white-color: #fff;
    --black-color: #000000;
    --Primary-color:#93CEE3;
    --onPrimary-color:#013542;
    --Primary-Container-color:#004E5F;
    --onPrimary-Container-color:#AFEBFF;
    --Secondary-color:#BBC9CD;
    --onSecondary-color:#253236;
    --Secondary-Container-color:#3C494D;
    --onSecondary-Container-color:#D7E5E9;
    --grey-dark-color: #434749;
    --grey-light-color: #C3C7C9;

    /* Size */
    --padding: 10px;
    --avatar-size:48px;

    /* Font Size */
    --font-large: 24px;
    --font-midium: 14px;
    --font-small: 12px;
    --font-micro: 10px;
}

...

header{
    position: sticky;
    top: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 5px var(--padding);
    background-color: var(--white-color);
    color: var(--black-color)

</code></pre>
<p>그리고 position: sticky 는 상위에 해당 요소를 고정해 주는 역할을 한다.
상단의 기준이 있어야 하기에 top: 0;으로 설정할 수 있다.</p>
<h3 id="display-flex">display: flex</h3>
<p>웹페이지의 레이아웃을 잡을 때 보통 display, float, position과 같은 css 속성들을 이용한다. 그런데 이러한 속성들로 레이아웃을 구현하는 게 몹시 복잡하거나 어려울 때가 있다. 그 한계를 극복하기 위해서 css3에 flex라는 방식이 새롭게 추가되었다. flexible box, flexbox라고도 부르는 flex는 레이아웃 배치 기능에 중점을 맞추어 고안되었기 때문에 기본 방식보다 훨씬 더 수월하게 퍼블리싱이 가능하다.</p>
<h3 id="hover">hover</h3>
<p>호버는 다음과 같이 효과를 주고자 하는 대상 뒤에 :hover를 붙여줌으로 커서가 위에 있는 것을 인식하여 반응할 수 있도록 해준다. </p>
<pre><code class="language-css">header .menu ul li:hover{
    background-color: var(--Primary-color);
    color: var(--white-color);
    border-radius: 5px;
}</code></pre>
<h3 id="position-absolute">position: absolute</h3>
<p>절대값으로 대상을 해당 위치에 고정시킨다. </p>
<pre><code class="language-css">header .toggleButton{
    text-decoration: none;
    display: none;
    position: absolute;
    font-size: 24px;
    top: 14px;
    right: 0px;
    color: var(--onPrimary-color);
}</code></pre>
<h3 id="clamp">clamp</h3>
<p>클램프는 텍스트의 내용이 초과 될 경우 그 줄을 제한할 수 있다.</p>
<pre><code class="language-css"> .info .metadata .titleAndButton .title.clamp{
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
}</code></pre>
<h3 id="transition-transform-transform-rotate">transition: transform, transform: rotate()</h3>
<p>클램프로 숨겨 둔 내용을 보여주는 moreButton 구현에서 썼다. 
단순하지만 동적으로 화살표가 위 아래로 회전할 수 있도록 했다. </p>
<p>transition은 전환 속도 곡선 지정을 통해 수학적으로 대상을 전환시킬 수 있다.
transition-timing-function 속성은 속도 곡선을 지정한다.</p>
<p>ease 느린 시작, 빠르게 시작, 느리게 종료하는 전환 효과를 지정(기본값).
linear 처음부터 끝까지 동일한 속도로 전환 효과를 지정
ease-in 느린 시작으로 전환 효과 지정
ease-out 느린 끝으로 전환 효과를 지정
ease-in-out 느린 시작과 끝으로 전환 효과 지정
cubic-bezier(n,n,n,n) 큐빅-베지어 함수에서 자신만의 값을 정의</p>
<p>Interactive Developer 실습을 했을 사용했던 효과이기에 이해하기 쉬웠다.</p>
<pre><code class="language-css">.info .metadata .titleAndButton .moreButton{
    height: 100%;
    transition: transform 300ms ease-in-out;
}
.info .metadata .titleAndButton .moreButton.clicked{
    transform: rotate(180deg);
}</code></pre>
<p>애플 홈페이지에 적용되었던 효과들이 플레이타임을 높이 값에 연동시켜 섬세하게 컨트롤한 것인가. 비디오 태그를 다루는 것에 좀 더 익숙해 질 수 있도록 하자.</p>
<h3 id="flex">flex</h3>
<p>플렉스에 따라서 해당 비율로 설정할 수 있다.</p>
<pre><code class="language-css">.upNext .item .video{
    flex: 1 1 35%;
    margin-right: var(--padding);
    min-width: 180px;
    min-height: 100px;
}
.upNext .item .info1{
    flex-direction: column;
    flex: 1 1 60%;
}
.upNext .item .moreButton{
    height: 100%;
    flex: 1 1 5%;
}</code></pre>
<h3 id="그리고-그-다음">그리고 그 다음</h3>
<p>유효성검사를 복습한다. DOM을 다루는 것을 살펴보자
그 다음은 마음에 들지 않는 푸터를 없애버리고 리액트를 다뤄봐야겠다. 
Up Next에 infinite scroll 할 수 있고, 각 게시물에 데이터에 
좋아요, 싫어요, 공유 저장 기능들을 활성화 할 수 있도록 만들어 보자. 
이 작업까지는 서버가 필요 없도록 더미데이터를 활용하겠지만 올 해 안으로 
서버까지 자유롭게 다룰 수 있도록 해야 한다. 웹 개발 A to Z 위해 다분히 손을 놀리자.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL]]></title>
            <link>https://velog.io/@nft_sb/TIL-ly3g8gu0</link>
            <guid>https://velog.io/@nft_sb/TIL-ly3g8gu0</guid>
            <pubDate>Tue, 11 Oct 2022 03:13:47 GMT</pubDate>
            <description><![CDATA[<p><a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Methods">MDN:HTTP 요청 메서드</a>
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Messages">MDN:HTTP메시지</a>
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Status">MDN:HTTP상태코드</a>
HTTP의 무상태성(stateless)
HTTP는 특정 상태를 담고 있지 않으며, 
이전 요청이나 다음 요청을 기억하지 않음.</p>
<p><a href="https://d2.naver.com/helloworld/59361">브라우저는 어떻게 동작하는가?</a>(이 글은 꽤나 흥미롭)</p>
<h3 id="ajax">Ajax</h3>
<p>Ajax란 Asynchronous JavaScript and XML의 약자.
Ajax는 빠르게 동작하는 동적인 웹 페이지를 만들기 위한 개발 기법.
Ajax는 웹 페이지 전체를 다시 로딩하지 않고도, 웹 페이지의 일부분만을 갱신.
Ajax를 이용하면 백그라운드 영역에서 서버와 통신하여, 그 결과를 웹 페이지의 일부분에만 표시.</p>
<p>이때 서버와는 다음과 같은 다양한 형태의 데이터를 주고받을 수 있음.</p>
<ul>
<li>JSON</li>
<li>XML</li>
<li>HTML</li>
<li>텍스트 파일 등</li>
</ul>
<h4 id="장점">장점</h4>
<ol>
<li>웹 페이지 전체를 다시 로딩하지 않고도, 웹 페이지의 일부분만을 갱신할 수 있음.</li>
<li>웹 페이지가 로드된 후에 서버로 데이터 요청을 보낼 수 있음.</li>
<li>웹 페이지가 로드된 후에 서버로부터 데이터를 받을 수 있음.</li>
<li>백그라운드 영역에서 서버로 데이터를 보낼 수 있음.</li>
</ol>
<h4 id="한계">한계</h4>
<p>Ajax로도 다음과 같은 일들은 처리할 수 없음.</p>
<ol>
<li>Ajax는 클라이언트가 서버에 데이터를 요청하는 클라이언트 풀링 방식을 사용하므로, 서버 푸시 방식의 실시간 서비스는 만들 수 없음.</li>
<li>Ajax로는 바이너리 데이터를 보내거나 받을 수 없음.</li>
<li>Ajax 스크립트가 포함된 서버가 아닌 다른 서버로 Ajax 요청을 보낼 수는 없음.</li>
<li>클라이언트의 PC로 Ajax 요청을 보낼 수는 없음.</li>
</ol>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">CORS:Cross-Origin Resource Sharing</a></p>
<p>REST API
<a href="https://cloud.google.com/apis/design?hl=ko">GOOGLE API GUIDE</a></p>
<p><img src="https://velog.velcdn.com/images/nft_sb/post/ed2d8828-59cf-4bbb-90e3-e428bef6b3ff/image.PNG" alt="">
ㅋㅋㅋㅋㅋ웃겨</p>
<p>7 Layers of OSI 
진짜 오랜만에 보네
지긋지긋한 포트넘버들ㅋㅋㅋㅋㅋ
헤더 나오길래 패킷구조까지 다루는가 했더니
얕아서 다행이야.</p>
<p>네트워크 일볼 때 생각난다
서버 스위치 라우트1 라우트2 스위치 PC연결하고 
라우터에서 서버에서 암호화하고 
동적 주소할당시키고 핑쏘고
벌써 몇 년 전이냐</p>
<p>빨리 끝났네!
리프레시에는 바다가 좋다
정리하자</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL]]></title>
            <link>https://velog.io/@nft_sb/TIL-oh94q12q</link>
            <guid>https://velog.io/@nft_sb/TIL-oh94q12q</guid>
            <pubDate>Sun, 09 Oct 2022 14:16:50 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/nft_sb/post/012bd747-fbf1-46c4-b7f6-2a3847b2cd88/image.jpg" alt=""></p>
<h1 id="reduce-활용하기">reduce 활용하기</h1>
<h2 id="함수형-프로그래밍">함수형 프로그래밍</h2>
<p>많은 분들이 forEach는 사용하시는데 map과 reduce는 잘 안 쓰시더라고요. 
그리고 reduce가 뭐냐고 물어보면 덧셈하는 함수 아니냐고 하시는 분도 많이 봤습니다. 
ㅠㅠ 그래서 오늘은 제가 제일 좋아하는 메서드인 map과 reduce에 대해 알아보겠습니다. 
제가 생각하기로는 자바스크립트 내장 메서드 중에서 제일 강력하고, 
알아두면 다양한 곳에 활용할 수 있는 것이 바로 map과 reduce입니다. 
얼마나 강력하냐면, 맵리듀스라고 이름지어진 프레임워크도 있습니다. 
(물론 오늘 다루는 내용은 아닙니다.)</p>
<h3 id="reduce-reduceright">reduce, reduceRight</h3>
<p>reduce를 덧셈 함수로 알고 계신 분들이 많은데, 
대부분의 사이트에서 reduce 사용 예시를 덧셈으로 들고 있기 때문입니다. 
심지어 저도 강좌에서 덧셈으로 예를 들었습니다... 
하지만 reduce는 알고보면 매우 강력한 친구입니다. 
함께 알아봅시다.</p>
<p>reduce 메서드는 다음과 같이 사용합니다. 
배열.reduce((누적값, 현잿값, 인덱스, 요소) =&gt; { return 결과 }, 초깃값);</p>
<p>이전값이 아니라 누적값이라는 것에 주의하셔야 합니다. 
누적값이기 때문에 다양하게 활용할 수 있습니다. 
먼저 흔한 덧셈 예시를 살펴봅시다.</p>
<pre><code>result = oneTwoThree.reduce((acc, cur, i) =&gt; {
  console.log(acc, cur, i);
  return acc + cur;
}, 0);
// 0 1 0
// 1 2 1
// 3 3 2
result; // 6</code></pre><p>acc(누적값)이 초깃값인 0부터 시작해서
return하는대로 누적되는 것을 볼 수 있습니다. 
초깃값을 적어주지 않으면 자동으로 초깃값이 0번째 인덱스의 값이 됩니다.</p>
<pre><code>result = oneTwoThree.reduce((acc, cur, i) =&gt; {
  console.log(acc, cur, i);
  return acc + cur;
});
// 1 2 1
// 3 3 2
result; // 6 </code></pre><p>초깃값을 적었을 때와 안 적었을 때의 차이점이 보시이죠?</p>
<p>reduceRight는 reduce와 동작은 같지만 요소 순회를 
오른쪽에서부터 왼쪽으로 한다는 점이 차이입니다.  </p>
<pre><code>result = oneTwoThree.reduceRight((acc, cur, i) =&gt; {
  console.log(acc, cur, i);
  return acc + cur;
}, 0);
// 0 3 2
// 3 2 1
// 5 1 0
result; // 6</code></pre><p>여기까지는 흔한 덧셈 예제이지만... 
reduce는 덧셈 곱셈만을 위한 것이 아닙니다. 
초깃값을 활용하여 어떤 일을 할 수 있는지 알아보겠습니다. 
map과 filter과 같은 함수형 메서드를 모두 reduce로 모두 구현할 수 있습니다.</p>
<p>위의 map 예제를 reduce로 만들어보겠습니다.</p>
<pre><code>result = oneTwoThree.reduce((acc, cur) =&gt; {
  acc.push(cur % 2 ? &#39;홀수&#39; : &#39;짝수&#39;);
  return acc;
}, []);
result; // [&#39;홀수&#39;, &#39;짝수&#39;, &#39;홀수&#39;]</code></pre><p>초깃값을 배열로 만들고, 배열에 값들을 push하면 map과 같아집니다. 
이를 응용하여 조건부로 push를 하면 filter와 같아집니다. 
다음은 홀수만 필터링하는 코드입니다.</p>
<pre><code>result = oneTwoThree.reduce((acc, cur) =&gt; {
  if (cur % 2) acc.push(cur);
  return acc;
}, []);
result; // [1, 3]</code></pre><p>이와 같이 sort, every, some, find, findIndex, includes도 
다 reduce로 구현 가능합니다. reduce가 이들 모두의 아버지였던 것입니다. ㅠㅠ</p>
<p>reduce는 비동기 프로그래밍을 할 때에도 유용합니다.</p>
<pre><code>const promiseFactory = (time) =&gt; {
  return new Promise((resolve, reject) =&gt; {
    console.log(time); 
    setTimeout(resolve, time);
  });
};
[1000, 2000, 3000, 4000].reduce((acc, cur) =&gt; {
  return acc.then(() =&gt; promiseFactory(cur));
}, Promise.resolve());
// 바로 1000
// 1초 후 2000
// 2초 후 3000
// 3초 후 4000</code></pre><p>초깃값을 Promise.resolve()로 한 후에,
return된 프로미스에 then을 붙여 다음 누적값으로 넘기면 됩니다. 
프로미스가 순차적으로 실행됨을 보장할 수 있습니다.</p>
<p>반복되는 모든 것에는 reduce를 쓸 수 있다는 것을 기억하시면 됩니다.</p>
<p>map과 reduce 외에도, 배열의 메서드인 
sort, filter, every, some, find, findIndex, includes 정도는 알아두시면 좋습니다. 
오늘 reduce만 있어도 다른 메서드들을 다 구현할 수 있다는 것을 배웠기 때문에, 
다른 메서드를 까먹으면 reduce로 구현하시면 됩니다!</p>
<p>출처 : <a href="https://www.zerocho.com/category/JavaScript/post/5acafb05f24445001b8d796d">reduce 예찬론자</a> </p>
<h3 id="til">TIL</h3>
<p>위 글 덕에 reduce에 대한 이해가 깊어졌다. 
이번 첫 HA 레퍼런스에서 이해하기 어려웠던 reduce 초깃값 부분</p>
<pre><code>        &lt;select onChange={handleCategoryChange}&gt;
          &lt;option value = &quot;전체보기&quot;&gt;전체보기&lt;/option&gt;
          {images.reduce(categoryReducer,[]).map(category =&gt;
            &lt;option value = {category} key = {category}&gt;{category}
            &lt;/option&gt;)
          }
        &lt;/select&gt;</code></pre><p>categoryReducer가 초깃값 빈배열에 담기고 그 내용이 옵션에 매핑 된다는 간단한 얘기
그러니까 왜 나는 초깃값에 할당된 배열을 cur로 생각한 건지. 도른자인가?
이걸로 몇 시간을 쓴거야
ㅋㅋㅋㅋㅋㅋㅋㅋ
아오 멍청아</p>
<p>진정하고.
<a href="https://velog.io/@yukyung/%EC%BD%94%EC%96%B4-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8A%A4%ED%84%B0%EB%94%94-%ED%9A%8C%EA%B3%A0">코어 자바스크립트</a>와 그 <a href="https://cozy60.notion.site/09adf19141354fb7ba946ea19b442177">기록</a>을 자세히 살펴 보자.
이런 스터디는 기회가 되면 참여 해 보고싶다. </p>
<p>이 글 덕에 오랫동안 묵혀두었던 
[HTML + CSS + Javascript 웹프로그래밍]을 다시 꺼내 본다.
붙캠 시작 전에 JS 객체부분만 좀더 딥하게 봤다면 
어땠을까.</p>
<p>MJ가 끊임 없이 코어를 말했던 이유를 알겠다.
코어에 대한 이해가 깊을수록 퍼포먼스 스펙트럼은 넓어진다.
이론 공부하며 실무 경험 투덜거릴 때 그녀가 말했지</p>
<h4 id="이론이-실무고-실무가-이론이다-공학이라는-게-그런거야">&quot;이론이 실무고 실무가 이론이다. 공학이라는 게 그런거야.&quot;</h4>
<p>당시에 재수없던 이 말이 현현하여 
좀 더 재수없게 다가온다.
딱 그 만큼 좀 더 공부하자.</p>
<h3 id="하루를-마치며">하루를 마치며</h3>
<p>흘러가는 상황을 보아하니.
과정은 로우 퍼포먼서에게 불친절 해 질 것이고. 
나는 답을 찾기 위해 헤매야 할 것이다. </p>
<p>nomade
nomade</p>
<p>다시 밤이 깊었으니
별을 보고 따라가자</p>
]]></description>
        </item>
    </channel>
</rss>