diff --git a/lib/forge-std b/lib/forge-std index 8e7bbe6..1801b05 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 f9687e3..39d819f 100644 --- a/week-01/dev/src/Counter.sol +++ b/week-01/dev/src/Counter.sol @@ -30,6 +30,7 @@ contract Counter { /// @notice 카운트를 1 증가시킵니다 /// @dev count 값을 1만큼 증가시키는 로직을 구현하세요 function increment() public { + count++; // TODO: count를 1 증가시키세요 // 힌트: count += 1; 또는 count = count + 1; 또는 count++; } @@ -37,6 +38,9 @@ contract Counter { /// @notice 카운트를 1 감소시킵니다 /// @dev count가 0일 때 감소시키면 언더플로우가 발생합니다 function decrement() public { + // require 작동방식 : 조건 체크 -> 실패시 revert OPCODE 반환 -> 에러코드 반환 + require(count>0,"Count cannot go below zero"); + count--; // TODO: count를 1 감소시키세요. 단, count가 0이면 revert해야 합니다. // 힌트: require(조건, "에러 메시지"); 를 사용하세요 // 힌트: require(count > 0, "Count cannot go below zero"); @@ -45,6 +49,7 @@ contract Counter { /// @notice 카운트를 0으로 초기화합니다 /// @dev count 값을 0으로 설정하는 로직을 구현하세요 function reset() public { + count = 0; // TODO: 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 0000000..23cc4dd --- /dev/null +++ b/week-01/quiz/quiz-01-solution.md @@ -0,0 +1,307 @@ +# 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, 트랜잭션은 atomic 하기때문에 보내는 상태가 전부 성공하거나 실패한다. +실패한다는 것은 전체가 원래 상태로 돌아온다는 말이다. 그럼에도 가스비는 소모된다. +그래서 Alice의 잔액은 가스비 정도 줄어들고, Bob의 잔액은 그대로다 + +--- + +## 문제 2: [이론] 결정론적 실행 (객관식) + +이더리움 EVM이 "결정론적(deterministic)"으로 실행된다는 것의 핵심 이유는 무엇인가요? + +**보기:** +A) 모든 노드가 같은 하드웨어를 사용해야 해서 +B) 같은 입력(트랜잭션)이 주어지면 모든 노드가 같은 결과(상태)를 도출해야 하므로 +C) 중앙 서버가 모든 계산을 수행하고 결과를 배포해서 +D) 트랜잭션이 항상 1초 안에 처리되어야 해서 + +**답변:** + +B, evm이 결정론적이지 않으면 같은 입력이 발생했을 때, 다른 output이 발생할 수 있다. +이렇게 되면, 각 노드들은 자신이 실행한 결과가 맞다고 생각하기 때문에 노드들의 합의가 일어나기 힘들다. + + +--- + +## 문제 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에 의해서도 호출 될 수 있기 때문에 뒤에 설명은 좀 애매하다고 생각합니다.) +CA는 오직 publickey만 가지고 private키를 가지지 않는다. 사실 어떤 코드를 보관하고 있는 보관소 정도라고 생각하면될 것이다. +트랜잭션이 실행되려면 private키를 가져야한다. + +--- + +## 문제 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 값이 올라가서 다른 트랜잭션은 잘못된 논스값에 서명을 한 것 이기때문에 무효가된다. +즉 먼저 처리되는 한개만 처리되고, 다른 한개는 받아들여지지 않는다. + + +--- + +## 문제 5: [이론] World State (객관식) + +World State에 대한 설명 중 올바른 것은? + +**보기:** +A) World State는 최신 100개 블록의 트랜잭션만 저장한다 +B) World State는 모든 계정의 현재 상태(주소 -> 상태 매핑)를 나타낸다 +C) World State는 EOA의 정보만 저장하고 CA 정보는 별도로 관리한다 +D) World State는 각 노드마다 다른 값을 가질 수 있다 + +**답변:** + +B,모든 계정의 정보는 unique 한 상태를 가진다. 이 상태들을 전부 모아놓은 것이 World State 이다. +전화번호 또한 한 사람 한 사람 unique 한 식별자이다. +따라서 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이고 지역변수는 result 이다. +상태변수는 Storage에 저장되고 지역변수는 Memory에 저장된다. +트랜잭션 종료 후 상태변수는 사라지지 않고, 지역 변수는 사라진다. +상태변수는 해당 Contract가 사라지기 전에 사라지지 않는다. +상태변수에 접근하는 것이 지역변수에 접근하는 것보다 비싸다. + + +--- + +## 문제 7: [이론] 원자성의 이유 (단답형) + +이더리움에서 트랜잭션이 "원자적(atomic)"으로 처리되어야 하는 이유는 무엇인가요? + +**왜** 부분적으로 성공하는 트랜잭션을 허용하면 문제가 될까요? 구체적인 예시와 함께 설명하세요. + +**답변:** + +Alice가 Bob에게 송금을 하는데, 트랜잭션이 절반만 성공해서 Alice의 잔액은 줄어들었는데 Bob의 계좌는 그대로인 경우가 있을 수 있다. 이러면 시스템적인 일관성과 신뢰성이 저해된다. +따라서 트랜잭션은 원자적으로 처리되어야한다. + + +--- + +## 문제 8: [이론] 계정 구조 설명 (단답형) + +EOA에는 `codeHash`와 `storageRoot`가 왜 의미가 없나요? + +**답변:** + +EOA는 컨트랙트 코드를 보유하지 않기 때문에 실행할 코드가 없다. 이로 인해 codeHash는 의미가없다. +EOA는 storage를 사용하지 않으므로 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`이 붙으면 어떤 일이 자동으로 일어나나요? + +**답변:** + +상태변수에 public을 붙이면 getter 함수를 자동으로 생성해준다. +그래서 외부에서 count값을 볼 수 있게된다. + + +**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()` 호출의 결과는 무엇인가요? + +**답변:** + +revert되고 "Count cannot go below zero"라는 오류메시지가 반환된다. +그 이유는 count값이 0->1->2->1->0 에서 decreasement()를 호출햇기 때문에 +require(count > 0, "Count cannot go below zero"); 에서 걸리게된다. + + +**질문 2:** 왜 `decrement()` 함수에 `require(count > 0, ...)` 조건이 필요한가요? + +**답변:** + + +uint256은 부호가 없는 256비트 정수형이다. 최소값은 0 이고 여기서 -르 해버리면 언더플로우가 발생해 +2^256-1 로 값이 튀어버린다. 따라서 require(count > 0, ...)조건이 필요하다. + + +--- + +## 자기 평가 + +모든 문제를 풀었다면, 아래 체크리스트로 자기 평가를 해보세요: + +- [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 0000000..3e9141c --- /dev/null +++ b/week-01/theory/quiz-01-solution.md @@ -0,0 +1,63 @@ +# 문제 1: 블록체인 기초 + +블록체인의 핵심 목적은 무엇인가요? 중앙화된 데이터베이스와 비교하여 설명해주세요. + +**답변:** +블록체인의 핵심 목적은 중앙 서버가 아닌 각각의 노드가 데이터를 보관하여 데이터의 무결성과 신뢰성을 보장하는 것이다. +중앙화된 데이터베이스는 중앙 서버가 모든 데이터를 관리하므로 중앙 서버에 대한 신뢰가 필요하다. +블록체인은 트렌젝션들을 블록으로 묶어서 해쉬포인터로 연결해놓은 것이다.이로 인해 악의적인 노드가 과거의 데이터를 수정하면 다른 노드들은 내부데이터의 변조를 알아 차릴 수 있다. 이로 인해 중앙 서버에 대한 신뢰가 필요없다(trustless) +대신 각 노드의 데이터베이스의 동기화(합의)를 위해 각각 체인내의 프로토콜에 따라 비용이 발생한다는 분산디비의 트레이드 오프를 생각해주어야한다. + +--- + +## 문제 2: 이더리움의 특징 + +이더리움이 비트코인과 다른 점은 무엇인가요? 스마트 컨트랙트의 관점에서 설명해주세요. + +**답변:** +이더리움과 비트코인의 가장 큰 차이점은 스마트 컨트랙트를 범용적으로 지원하는가에 대한 차이가 있다. + +비트코인이 사실 컨트랙트가 불가능한것은 아니다. 멀티시그나 타임락 그리고 script내에서 OPCODE로 분기를 내릴 수 있다.비트코인 script 내에서 쓸 수 잇는 OPCODE는 굉장히 한정적이고 스택기반으로 작동한다. +이로 인해, 제한적으로만 스마트 컨트랙트가 가능하다. + +반면에, 이더리움은 반복문 조건문등을 모두 사용할 수 있으며 가스를 통해 실행시간을 유한하게 제한한다. +이더리움은 Contract만을 위한 CA라는 계정이 따로 존재하고 (비트코인은 없음) 그 계정은 오직 트랜잭션을 받아야만 활성화 되며 트랜잭션을 받으면 evm내에서 CA에 있는 코드가 돌아가 상태를 변화 시킨다. + +--- + +## 문제 3: Solidity 기초 + +다음 Solidity 코드에서 `public`과 `view` 키워드의 의미를 각각 설명하세요. + +public + +```solidity +function count() public view returns (uint256) { + return _count; +} +``` + +**답변:** +- `public`: 함수가 내트워크 내부와 EOA 또는 다른 컨트랙트에서도 모두에서 호출 가능하다. +- `view`: Read Only -> 수정 불가,읽기 가능 + +--- + +## 문제 4: 상태 변수 + +Solidity에서 상태 변수(state variable)와 지역 변수(local variable)의 차이점을 설명하세요. + +**답변:** +[여기에 답변을 작성하세요] +상태 변수는 전역변수 즉, 함수 외부, 컨트랙트 내부에 존재, 컨트랙트가 사라지기 전까지 존재, 블록체인의 storage에 존재 +지역 변수는 지역변수 즉, 함수 내부에 존재 함수가 끝나면 메모리에서 사라짐 +--- + +## 문제 5: Gas 개념 + +이더리움에서 Gas란 무엇이며, 왜 필요한가요? + +**답변:** +[여기에 답변을 작성하세요] +gas는 트랜잭션을 이행하기위한 비용의 단위이며 evm내에서 컨트랙트 코드를 수행할때 하나의 연산을 할 때마다 gas 를 소모한다. +gas는 evm 내에서 무한루프나 너무 복잡한 시스템을 구동하지 못하도록 하기 위해 반드시 필요하다. gas가 소진되면 트랜잭션은 revert 된다. 이로 인해, 이더리움은 튜링 완전하면서 안정적인 네트워크를 유지 할 수 있다. \ No newline at end of file