diff --git a/week-01/dev/src/Counter.sol b/week-01/dev/src/Counter.sol index f9687e3a..77da51dd 100644 --- a/week-01/dev/src/Counter.sol +++ b/week-01/dev/src/Counter.sol @@ -27,25 +27,16 @@ contract Counter { // 쓰기 함수 (State-Changing Functions) // ============================================================ - /// @notice 카운트를 1 증가시킵니다 - /// @dev count 값을 1만큼 증가시키는 로직을 구현하세요 function increment() public { - // TODO: count를 1 증가시키세요 - // 힌트: count += 1; 또는 count = count + 1; 또는 count++; + count += 1; } - /// @notice 카운트를 1 감소시킵니다 - /// @dev count가 0일 때 감소시키면 언더플로우가 발생합니다 function decrement() public { - // TODO: count를 1 감소시키세요. 단, count가 0이면 revert해야 합니다. - // 힌트: require(조건, "에러 메시지"); 를 사용하세요 - // 힌트: require(count > 0, "Count cannot go below zero"); + require(count > 0, "Count cannot go below zero"); + count -= 1; } - /// @notice 카운트를 0으로 초기화합니다 - /// @dev count 값을 0으로 설정하는 로직을 구현하세요 function reset() public { - // TODO: count를 0으로 초기화하세요 - // 힌트: count = 0; + count = 0; } } diff --git a/week-01/quiz/quiz-01-solution.md b/week-01/quiz/quiz-01-solution.md new file mode 100644 index 00000000..0aa5322f --- /dev/null +++ b/week-01/quiz/quiz-01-solution.md @@ -0,0 +1,292 @@ +# Week 1 퀴즈: State/Account + Solidity 기초 + +**제출 방법:** +1. 이 파일을 복사하여 `quiz-01-solution.md`로 저장 +2. 각 문제에 답변 작성 (왜 그런지 설명 포함) +3. Pull Request 생성 (`quiz_submission` 템플릿 사용) + +**평가 기준:** +- 정답 여부보다 **개념 이해도**를 중점 평가합니다 +- "왜"에 대한 설명이 충분한지 확인합니다 +- 문법 오류는 크게 감점하지 않습니다 + +--- + +## 문제 1: [이론] 상태 머신 (객관식) + +이더리움에서 "상태 전이가 원자적(atomic)이다"라는 말의 의미를 가장 잘 설명한 것은? + +다음 상황을 고려하세요: + +``` +Alice가 Bob에게 1 ETH를 보내는 트랜잭션을 실행합니다. +중간에 가스가 부족해져서 트랜잭션이 실패했습니다. +``` + +**보기:** +A) Alice의 잔액만 감소하고 Bob의 잔액은 변하지 않는다 +B) Alice의 잔액과 Bob의 잔액 모두 변하지 않고, 가스비만 소모된다 +C) 네트워크가 자동으로 부족한 가스를 보충해서 트랜잭션을 완료한다 +D) 트랜잭션이 절반만 실행되어 0.5 ETH만 전송된다 + +**답변:** + + +B) Gas는 트랜잭션 실행에 필요한 컴퓨팅 자원에 대한 비용으로 상태 전이의 성공 여부와 관계없이 실제 수행된 연산량에 비례하여 소모된다. 따라서 트랜잭션이 실패하면 상태는 실행 이전으로 되돌아가고 이미 사용된 자원에 대한 비용인 Gas는 환불되지 않는다. + +상태 전이가 원자적이라는 것은 모든 변경이 전부 성공하거나 전부 실패한다는 것이다. 트랜잭션 실행 중 하나라도 실패하면 전체가 롤백되어 부분적인 상태 변경을 방지함으로써 강한 일관성(Consistency)을 보장할 수 있다. + +--- + +## 문제 2: [이론] 결정론적 실행 (객관식) + +이더리움 EVM이 "결정론적(deterministic)"으로 실행된다는 것의 핵심 이유는 무엇인가요? + +**보기:** +A) 모든 노드가 같은 하드웨어를 사용해야 해서 +B) 같은 입력(트랜잭션)이 주어지면 모든 노드가 같은 결과(상태)를 도출해야 하므로 +C) 중앙 서버가 모든 계산을 수행하고 결과를 배포해서 +D) 트랜잭션이 항상 1초 안에 처리되어야 해서 + +**답변:** + + +B) 만약 EVM이 비결정론적으로 실행되어 같은 입력에 대해 노드마다 서로 다른 결과를 낸다면 동일한 트랜잭션에 대해서도 각 노드에서 서로 다른 상태 전이가 발생하게 된다. 이러한 상태 불일치는 블록 검증을 불가능하게 만들고 합의를 깨뜨려 네트워크 전체의 일관성을 훼손한다. 결과적으로 블록체인의 신뢰성과 무결성이 붕괴된다. +--- + +## 문제 3: [이론] EOA vs CA (객관식) + +다음 중 EOA(Externally Owned Account)와 CA(Contract Account)의 차이를 올바르게 설명한 것은? + +**보기:** +A) EOA는 코드를 실행할 수 있고, CA는 코드를 실행할 수 없다 +B) EOA만 트랜잭션을 시작할 수 있고, CA는 EOA에 의해 호출될 때만 실행된다 +C) CA만 ETH를 보유할 수 있고, EOA는 ETH를 보유할 수 없다 +D) EOA와 CA는 동일한 기능을 가지며 이름만 다르다 + +**답변:** + + +B) CA는 개인 키를 보유하지 않기 때문에 트랜잭션에 필요한 디지털 서명을 생성할 수 없다. 이더리움에서 트랜잭션을 시작하려면 개인 키로 서명하여 해당 요청이 계정 소유자로부터 발생했음을 증명해야 한다. 그러나 CA는 코드로만 제어되는 계정이므로 스스로 서명하거나 트랜잭션을 생성할 수 없으며 반드시 EOA로부터 호출을 받아야 실행된다. +--- + +## 문제 4: [이론] 계정 상태 필드 (객관식) + +이더리움 계정 상태의 4가지 필드 중 `nonce`의 역할을 올바르게 설명한 것은? + +다음 상황을 고려하세요: + +``` +Alice의 현재 nonce: 5 +Alice가 두 개의 트랜잭션을 동시에 전송합니다: +- TX-A: nonce=5, Bob에게 1 ETH 전송 +- TX-B: nonce=5, Charlie에게 2 ETH 전송 +``` + +**보기:** +A) 두 트랜잭션 모두 성공적으로 처리된다 +B) TX-A만 처리되고 TX-B는 무시된다 (또는 그 반대) +C) 두 트랜잭션 모두 실패하고 Alice의 자산이 동결된다 +D) 네트워크가 자동으로 TX-B의 nonce를 6으로 변경한다 + +**답변:** + + +B) nonce는 각 계정이 발생시키는 트랜잭션에 부여되는 고유한 순번으로 한 번 사용된 nonce는 다시 사용할 수 없다. 따라서 과거에 전송된 트랜잭션을 복사해 이중 지불 공격을 시도하더라도 이미 처리된 nonce를 가진 트랜잭션은 네트워크에서 거부된다. + +--- + +## 문제 5: [이론] World State (객관식) + +World State에 대한 설명 중 올바른 것은? + +**보기:** +A) World State는 최신 100개 블록의 트랜잭션만 저장한다 +B) World State는 모든 계정의 현재 상태(주소 -> 상태 매핑)를 나타낸다 +C) World State는 EOA의 정보만 저장하고 CA 정보는 별도로 관리한다 +D) World State는 각 노드마다 다른 값을 가질 수 있다 + +**답변:** + + +B) 계정 주소를 기준으로 해당 계정의 상태를 바로 조회할 수 있는 구조로 계정 주소를 키로 하여 잔액(balance), nonce, 코드(codeHash), 스토리지(storageRoot)와 같은 상태 정보를 확인할 수 있다. + +--- + +## 문제 6: [이론] 상태 변수 vs 지역 변수 (단답형) + +Solidity에서 `상태 변수(state variable)`와 `지역 변수(local variable)`의 차이는 무엇인가요? + +다음 코드를 보고 설명하세요: + +```solidity +contract Example { + uint256 public count; // 이것은 무엇인가요? + + function calculate(uint256 input) public pure returns (uint256) { + uint256 result = input * 2; // 이것은 무엇인가요? + return result; + } +} +``` + +**답변:** + + +count는 상태 변수, result는 지역 변수이다. + +상태 변수인 count는 컨트랙트 내부에 선언된 전역 변수로 EVM의 스토리지에 저장되며 블록체인에 영구적으로 기록된다. 따라서 트랜잭션이 종료된 이후에도 값이 유지되고 모든 함수에서 접근할 수 있다. 스토리지에 데이터를 기록하거나 수정하는 작업은 많은 가스를 요구하므로 비용이 상대적으로 높다. + +result는 함수 내부에서 선언된 지역 변수로 메모리에 일시적으로 저장된다. 블록체인에 기록되지 않으며 함수 실행이 끝나면 사라지는 임시 데이터이다. 또한 스토리지를 사용하지 않기 때문에 비용이 저렴하다. +--- + +## 문제 7: [이론] 원자성의 이유 (단답형) + +이더리움에서 트랜잭션이 "원자적(atomic)"으로 처리되어야 하는 이유는 무엇인가요? + +**왜** 부분적으로 성공하는 트랜잭션을 허용하면 문제가 될까요? 구체적인 예시와 함께 설명하세요. + +**답변:** + + +이더리움에서 트랜잭션이 원자적으로 처리되어야 하는 이유는 상태의 정합성과 시스템 신뢰성을 보장하기 위해서이다. 만약 트랜잭션이 부분적으로만 성공한다면 계정 간 잔액이나 컨트랙트 상태가 서로 맞지 않는 문제가 발생한다. 예를 들어 송금 과정에서 보내는 사람의 잔액은 차감되었지만 받는 사람의 잔액이 증가하지 않는다면 자산의 총량이 깨지는 문제가 발생한다. 이러한 정합성 문제는 네트워크 전체의 합의를 어렵게 만들고 블록체인 시스템의 신뢰를 훼손하므로 트랜잭션은 반드시 모두 성공하거나 모두 실패하도록 처리되어야 한다. + +--- + +## 문제 8: [이론] 계정 구조 설명 (단답형) + +EOA에는 `codeHash`와 `storageRoot`가 왜 의미가 없나요? + +**답변:** + + +EOA는 사용자가 개인키로 트랜잭션을 생성하고 서명하는 계정으로 코드나 상태 변수를 저장하지 않는다. 따라서 스마트 컨트랙트의 바이트코드를 나타내는 codeHash와 상태 데이터를 저장하는 storageRoot는 EOA에서 의미가 없다. 반면 CA는 코드와 스토리지를 기반으로 스마트 컨트랙트를 실행하는 계정이므로 두 값이 모두 필요하다. + +--- + +## 문제 9: [코드] Counter 읽기 (코드 읽기) + +다음 Counter.sol 코드를 분석하세요: + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +contract Counter { + uint256 public count; + + function getCount() public view returns (uint256) { + return count; + } + + function increment() public { + count += 1; + } + + function decrement() public { + require(count > 0, "Count cannot go below zero"); + count -= 1; + } +} +``` + +**1) `public` 키워드의 역할:** +`count` 변수에 `public`이 붙으면 어떤 일이 자동으로 일어나나요? + +**답변:** + +count 변수가 public으로 선언되면 Solidity가 자동으로 getter 함수를 생성한다. 이 함수는 외부에서 count() 형태로 호출할 수 있어 별도의 조회 함수를 작성하지 않아도 현재 값을 확인할 수 있다. 또한 생성된 getter는 읽기 전용 함수로 제공되므로 count() 호출만으로 외부에서 직접 값을 변경할 수는 없다. + +**2) `view` 키워드의 의미:** +`getCount()` 함수에 `view`가 붙은 이유는 무엇인가요? `view`를 제거하면 어떻게 될까요? + +**답변:** + +view는 해당 함수가 컨트랙트의 상태를 변경하지 않고 조회만 수행함을 의미한다. 따라서 별도의 트랜잭션으로 실행하지 않고 RPC 노드의 eth_call 방식으로 Gas 비용 없이 결과를 받을 수 있다. 또한 Solidity 컴파일러는 view 함수 내부에서 상태 변경이 발생하지 않도록 컴파일 단계에서 검사하여 함수의 안전성과 예측 가능성을 보장한다. 만약 view를 제거하더라도 호출 자체는 가능하지만 상태 변경 가능성을 컴파일러 수준에서 제한할 수 없고, 읽기 전용 함수라는 개발자의 의도를 명확히 전달하지 못해 비효율적인 설계를 유도할 수 있다. + +--- + +## 문제 10: [코드] Counter 동작 예측 (코드 읽기) + +위의 Counter 컨트랙트에서 다음 시나리오를 분석하세요: + +**시나리오:** +``` +초기 상태: count = 0 + +1. increment() 호출 +2. increment() 호출 +3. decrement() 호출 +4. decrement() 호출 +5. decrement() 호출 +``` + +**질문 1:** 5번째 `decrement()` 호출의 결과는 무엇인가요? + +**답변:** + + +실패, 다섯 번째 decrement() 호출 시 count는 이미 0이므로 require(count > 0) 조건을 만족하지 못한다. require 조건을 만족하지 못하면 revert가 발생하여 트랜잭션 전체가 취소되고 모든 상태 변경이 롤백된다. 따라서 "Count cannot go below zero"라는 에러 메시지가 전달되며 count는 마지막 decrement() 실행 전 값인 0으로 유지된다. + +**질문 2:** 왜 `decrement()` 함수에 `require(count > 0, ...)` 조건이 필요한가요? + +**답변:** + + +require(count > 0) 조건은 count가 0일 때 감소 연산이 실행되는 것을 방지하기 위해 필요하다. count는 음수를 표현할 수 없는 unsigned 정수인 uint256 타입이므로 0에서 1을 빼면 언더플로우가 발생한다. 이때 wrap-around로 인해 MSB가 1인 매우 큰 값으로 계산되며 의도와 다른 상태 전이를 초래한다. 결과적으로 상태 무결성이 훼손되어 시스템의 신뢰성과 보안에 심각한 문제가 발생할 수 있다. + + +--- + +## 자기 평가 + +모든 문제를 풀었다면, 아래 체크리스트로 자기 평가를 해보세요: + +- [v] 상태 머신과 원자성 개념을 이해했다 +- [v] EOA와 CA의 차이를 설명할 수 있다 +- [v] 계정 상태의 4가지 필드(nonce, balance, storageRoot, codeHash)를 이해했다 +- [v] Solidity 기본 문법(public, view, require)을 이해했다 +- [v] 상태 변수와 지역 변수의 차이를 설명할 수 있다 + +--- + +## 참고 자료 + +- 이론: `eth-materials/week-01/theory/slides.md` +- 코드: `eth-homework/week-01/dev/src/Counter.sol` +- 용어: `eth-materials/resources/glossary.md` diff --git a/week-01/theory/quiz-01-solution.md b/week-01/theory/quiz-01-solution.md new file mode 100644 index 00000000..7c754204 --- /dev/null +++ b/week-01/theory/quiz-01-solution.md @@ -0,0 +1,60 @@ +# Week 1 이론 퀴즈 + +이 퀴즈를 복사하여 `quiz-01-solution.md`로 저장한 후 답변을 작성하세요. + +--- + +## 문제 1: 블록체인 기초 + +블록체인의 핵심 목적은 무엇인가요? 중앙화된 데이터베이스와 비교하여 설명해주세요. + +**답변:** + +중앙 관리자 없이 분산 환경에서 동일한 데이터를 공유하고 검증하기 위함이다. 중앙화된 데이터베이스는 신뢰를 전제한 기관이 데이터를 통제하고 관리하는 구조로 처리 속도가 빠르고 운영 효율성이 높지만 단일 장애 지점이 존재하며 관리자에 의한 데이터 변조 위험이 있다. 반면 블록체인은 여러 참여자가 합의 과정을 통해 데이터를 검증하고 분산 저장하므로 위변조가 어렵고 투명성이 높아 특정 기관에 대한 신뢰 없이도 데이터의 신뢰성을 확보할 수 있다. + +## 문제 2: 이더리움의 특징 + +이더리움이 비트코인과 다른 점은 무엇인가요? 스마트 컨트랙트의 관점에서 설명해주세요. + +**답변:** + +비트코인은 UTXO 모델 기반으로 설계되어 단순하고 안전한 거래 처리에 집중하며 주로 송금을 목적으로 한다. 반면 이더리움은 Account 모델 기반으로 스마트 컨트랙트를 통해 특정 조건에서 자동 실행되는 프로그램을 블록체인 위에 배포할 수 있도록 설계된 탈중앙 애플리케이션 실행 플랫폼이다. 따라서 비트코인이 결제, 송금 중심의 블록체인이라면, 이더리움은 다양한 서비스와 애플리케이션을 구현할 수 있는 범용 블록체인이다. + + +## 문제 3: Solidity 기초 + +다음 Solidity 코드에서 `public`과 `view` 키워드의 의미를 각각 설명하세요. + +```solidity +function count() public view returns (uint256) { + return _count; +} +``` + +**답변:** +- `public`: 함수의 접근 제한자로 해당 함수가 컨트랙트 내부뿐만 아니라 외부 계정에서도 호출할 수 있도록 접근 범위를 설정하는 키워드이다. +- `view`: 함수의 변경 제한자로 해당 함수가 블록체인의 상태를 변경하지 않고 저장된 데이터를 읽기만 하는 읽기 전용 함수임을 나타내는 키워드이다. + + +## 문제 4: 상태 변수 + +Solidity에서 상태 변수(state variable)와 지역 변수(local variable)의 차이점을 설명하세요. + +**답변:** + +상태 변수는 컨트랙트 내부에 선언되는 전역 변수로 EVM의 스토리지에 저장되어 블록체인에 영구적으로 기록되는 변수이다. 컨트렉트 내부 모든 함수에서 접근 가능하며 트랜잭션을 통해 값이 변경되면 네트워크에 기록된다. 반면 지역 변수는 함수 내부에서 선언되며 주로 EVM의 스택 또는 메모리에 일시적으로 저장된다. 블록체인에 기록되지 않고 함수가 종료되면 소멸하는 임시 데이터이다. + + +## 문제 5: Gas 개념 + +이더리움에서 Gas란 무엇이며, 왜 필요한가요? + +**답변:** + +이더리움은 애플리케이션 실행 플랫폼으로서 스마트 컨트랙트의 실행 시 네트워크 자원을 소모한다. 튜링 완전성을 갖는 이더리움에서는 악의적으로 무한 루프와 같은 연산을 수행하여 네트워크에 부하를 줄 수 있는데, 이를 방지하기 위해 컴퓨팅 자원을 수치화한 비용이 Gas이다. Gas는 트랜잭션 처리나 스마트 컨트랙트 실행에 필요한 필요한 연산 비용을 측정하는 단위이며 사용자는 수행하려는 연산량에 따라 Gas를 지불한다. 이는 결과적으로 무한 루프와 같은 악의적인 연산을 방지하고 네트워크 자원의 남용을 막아 시스템의 안정성과 효율성을 유지하는 역할을 한다. + +**제출 방법:** +1. 이 파일을 복사하여 `quiz-01-solution.md`로 저장 +2. 각 문제에 대한 답변 작성 +3. Git으로 커밋 및 푸시 +4. Pull Request 생성