From 478a6dfc77fb19848b011e94731f85526cdd37d6 Mon Sep 17 00:00:00 2001 From: jaesimin Date: Thu, 5 Feb 2026 20:20:31 +0900 Subject: [PATCH] feat(week-01): complete counter assignment --- lib/forge-std | 2 +- week-01/dev/src/Counter.sol | 11 ++ week-01/theory/quiz-01-solution.md | 279 +++++++++++++++++++++++++++++ 3 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 week-01/theory/quiz-01-solution.md diff --git a/lib/forge-std b/lib/forge-std index 8e7bbe65..1801b054 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit 8e7bbe65b08aa71a0c93b50dc707da716a2ac1ff +Subproject commit 1801b0541f4fda118a10798fd3486bb7051c5dd6 diff --git a/week-01/dev/src/Counter.sol b/week-01/dev/src/Counter.sol index f9687e3a..95e8ceb1 100644 --- a/week-01/dev/src/Counter.sol +++ b/week-01/dev/src/Counter.sol @@ -13,6 +13,8 @@ contract Counter { /// @dev public으로 선언하면 자동으로 getter 함수가 생성됩니다 uint256 public count; + error CountCannotGoBelowZero(); + // ============================================================ // 읽기 함수 (View Functions) // ============================================================ @@ -32,6 +34,7 @@ contract Counter { function increment() public { // TODO: count를 1 증가시키세요 // 힌트: count += 1; 또는 count = count + 1; 또는 count++; + count += 1; } /// @notice 카운트를 1 감소시킵니다 @@ -40,6 +43,13 @@ contract Counter { // TODO: count를 1 감소시키세요. 단, count가 0이면 revert해야 합니다. // 힌트: require(조건, "에러 메시지"); 를 사용하세요 // 힌트: require(count > 0, "Count cannot go below zero"); + + //error event 를 통해 에러 원인을 파악한다. 근데 이러면 if-else 로 인한 코드가 늘어나 가스비가 더 는다. 하지만, 에러 이벤트 파악하기좋아서 구조에따라 사용된다. + // if (count <= 0) { + // revert CountCannotGoBelowZero(); + // } + require(count > 0, "Count cannot go below zero"); + count -= 1; } /// @notice 카운트를 0으로 초기화합니다 @@ -47,5 +57,6 @@ contract Counter { function reset() public { // TODO: count를 0으로 초기화하세요 // 힌트: count = 0; + count = 0; } } diff --git a/week-01/theory/quiz-01-solution.md b/week-01/theory/quiz-01-solution.md new file mode 100644 index 00000000..5ec48f39 --- /dev/null +++ b/week-01/theory/quiz-01-solution.md @@ -0,0 +1,279 @@ +# 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 : 최초에 전송 가스비는 소모되지만, 트랜잭션이 실패했기 때문에 Bob의 잔액은 변하지 않고, Alice의 잔액도 변하지 않는다. 즉, 트랜잭션이 원자적으로 처리되었기 때문에 부분적으로 성공하는 경우가 없다. + +--- + +## 문제 2: [이론] 결정론적 실행 (객관식) + +이더리움 EVM이 "결정론적(deterministic)"으로 실행된다는 것의 핵심 이유는 무엇인가요? + +**보기:** +A) 모든 노드가 같은 하드웨어를 사용해야 해서 +B) 같은 입력(트랜잭션)이 주어지면 모든 노드가 같은 결과(상태)를 도출해야 하므로 +C) 중앙 서버가 모든 계산을 수행하고 결과를 배포해서 +D) 트랜잭션이 항상 1초 안에 처리되어야 해서 + +**답변:** + +B : 결정론적이라는 것은 같은 입력이 주어지면 항상 같은 결과가 나와야 한다는 뜻이다. 만약 결정론적이지 않으면, 노드 A와 노드 B가 다른 결과를 얻게 되고, 이로 인해 블록체인의 합의가 깨지게 된다. 즉, 블록체인의 무결성이 훼손된다. + +--- + +## 문제 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는 EOA에 의해 호출될 때만 실행된다. 왜냐하면 CA는 private key를 가지고 있지 않기 때문에 트랜잭션을 시작할 수 없다. +A 는 요즘엔 애매한게 EIP 7702로 인해서 가능해질 수 있다. EOA 가 트랜잭션 실행시 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는 트랜잭션의 순서를 보장하고, 중복 트랜잭션을 방지하는 역할을 한다. + +--- + +## 문제 5: [이론] World State (객관식) + +World State에 대한 설명 중 올바른 것은? + +**보기:** +A) World State는 최신 100개 블록의 트랜잭션만 저장한다 +B) World State는 모든 계정의 현재 상태(주소 -> 상태 매핑)를 나타낸다 +C) World State는 EOA의 정보만 저장하고 CA 정보는 별도로 관리한다 +D) World State는 각 노드마다 다른 값을 가질 수 있다 + +**답변:** + +B : World State는 모든 계정의 현재 상태(주소 -> 상태 매핑)를 나타낸다. 즉, World State는 이더리움 네트워크의 모든 계정 정보를 담고 있는 데이터베이스이다. + +--- + +## 문제 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 는 상태 변수이고 storage 에 저장된다. 트랜잭션이 종료된 후에도 유지된다. 비용이 더 비싸다. +result 는 지역 변수이고 memory 에 저장된다. 트랜잭션이 종료되면 사라진다. 비용이 더 저렴하다. + +--- + +## 문제 7: [이론] 원자성의 이유 (단답형) + +이더리움에서 트랜잭션이 "원자적(atomic)"으로 처리되어야 하는 이유는 무엇인가요? + +**왜** 부분적으로 성공하는 트랜잭션을 허용하면 문제가 될까요? 구체적인 예시와 함께 설명하세요. + +**답변:** + +만약 1이더를 송금하는 트랜잭션이 절반만 성공한다면, 0.5이더는 송금되고 0.5이더는 사라지게 된다. 이는 이더리움 네트워크의 무결성을 훼손하기 때문에 사용자들이 블록체인에 대한 신뢰를 잃게 된다. 따라서 트랜잭션은 원자적으로 처리되어야 한다. + +--- + +## 문제 8: [이론] 계정 구조 설명 (단답형) + +EOA에는 `codeHash`와 `storageRoot`가 왜 의미가 없나요? + +**답변:** + +EOA 는 private key 로 트랜잭션을 시작하고, CA는 EOA에 의해 호출될 때만 실행된다. 따라서 EOA는 codeHash와 storageRoot가 필요없다. 반면 CA는 코드를 가지고 있고, 상태를 저장해야 하기 때문에 codeHash와 storageRoot가 필요하다. + +--- + +## 문제 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 변수에 접근할 수 있는 getter 함수가 자동으로 생성된다. + +**2) `view` 키워드의 의미:** +`getCount()` 함수에 `view`가 붙은 이유는 무엇인가요? `view`를 제거하면 어떻게 될까요? + +**답변:** + +view 함수는 읽기 전용 함수다. 즉, 상태 변수를 변경하지 않는다. 따라서 트랜잭션을 발생시키지 않고, 가스비도 들지 않는다. 만약 view를 제거하면 트랜잭션을 발생시켜야 하고, 가스비도 든다. + +--- + +## 문제 10: [코드] Counter 동작 예측 (코드 읽기) + +위의 Counter 컨트랙트에서 다음 시나리오를 분석하세요: + +**시나리오:** +``` +초기 상태: count = 0 + +1. increment() 호출 +2. increment() 호출 +3. decrement() 호출 +4. decrement() 호출 +5. decrement() 호출 +``` + +**질문 1:** 5번째 `decrement()` 호출의 결과는 무엇인가요? + +**답변:** + +0보다 커야한다는 조건문에 의해 revert 된다. + +**질문 2:** 왜 `decrement()` 함수에 `require(count > 0, ...)` 조건이 필요한가요? + +**답변:** + +uint256은 0보다 작아질 수 없기 때문에, 0에서 1을 빼면 오버플로우가 발생하여 매우 큰 수가 된다. 따라서 require 조건이 필요하다. + +--- + +## 자기 평가 + +모든 문제를 풀었다면, 아래 체크리스트로 자기 평가를 해보세요: + +- [o] 상태 머신과 원자성 개념을 이해했다 +- [o] EOA와 CA의 차이를 설명할 수 있다 +- [o] 계정 상태의 4가지 필드(nonce, balance, storageRoot, codeHash)를 이해했다 +- [o] Solidity 기본 문법(public, view, require)을 이해했다 +- [o] 상태 변수와 지역 변수의 차이를 설명할 수 있다 + +--- + +## 참고 자료 + +- 이론: `eth-materials/week-01/theory/slides.md` +- 코드: `eth-homework/week-01/dev/src/Counter.sol` +- 용어: `eth-materials/resources/glossary.md`