kkamagi's story

IT, 정보보안, 포렌식, 일상 공유

Blockchain & CryptoCurrencies

하드포크란 무엇인가?

까마기 2024. 3. 3. 17:51
반응형

오늘은 하드포크 (Hard Fork)와 소프트 포크(Soft Fork)에 대해서 비교를 해볼가 합니다.

암호화폐 시장에서 시세나 일정을 검색하다 보면 비트코인 하드포크 일정, 비트코인캐시와 같은 말들이 나오게 됩니다.이때 하드포크 (Hard Fork)가 무엇인지 소프트 포크(Soft Fork)가 무엇인지 궁금하실거라고 생각합니다.그래서 이 두개를 쉽게 구분하도록 설명해 드리려고 합니다.

먼저 포크(Fork)란 우리가 흔이 알고있는 식사하실때 쓰는 포크와 스펠링이 똑같습니다.그런데 포크의 다른뜻으로는 분기점이라는 뜻도 있습니다.즉 포크가 일어난다는것은 새로운 분기점이 일어난다고 볼수가 있습니다.

포크가 일어나는 이유는 다양합니다. 이전의 규칙에서 새로운 규칙으로 넘어간다는 점에서는 똑같습니다.

그렇다면 소프트포크는 무엇일가요? 새로운 규칙에 따라 새롭게 생긴 코인이 이전에 사용되던 코인과 연결되어 계속 사용하게 됩니다.즉 이전에 사용되던 코인과 부드럽게 연결되어 그대로 사용할수 있는 것입니다.조금만 바뀌는 업그레이드와 똑같다고 생각하시면 됩니다.사용자로서는 달라지는게 거의 없이 업데이트된 코인을 그대로 쓰면 되고 채굴자들만 조금의 업그레이드를 해주면 됩니다. 소프트포크가 일어나게 되면 그냥 사용하시면 편한 이유는 이전 시스템과 화환이 가능하기 때문입니다.하지만 이 때문인지 큰 호재라고 받아들이는 경향이 적고 가격상승 없이 넘어가는 경우도 많습니다.

반면 하드포크는 새롭게 생긴 코인이 이전에 사용되던 코인과 공동되지 않는 것입니다.그래서 아예 새로운 코인이 나왔다고 생각하시면 됩니다.예를 들면 이더리움이 하드코프를 하여 새롭게 생긴 코인이 이더리움 클래식 입니다. 이전 규칙에서 지금 현재 아예 따로 분류되어 거래가 되는 것과 같이 새로운 코인이 만들어 지는것입니다.가장 중요한것은 하드포크가 일어나기전 비트코인을 가지고 있었다면 비트코인은 그대로 가지고 있으면서 비트코인캐시를 새롭게 받게 됩니다. 이 때문에 새로운 코인을 받는 호재로 사람들이 인식을 하기 시작했고 실제로 비트코인골드, 비트코인다이와 같이 하드포크가 일어났을때 가격상승을 나타내기도 했습니다.

하지만 하드포크가 있다고 해서 100% 가격상승을 나타내는 것은 아니기 때문에 참고해서 투자하시길 바랍니다.

여기서 이더리움에 대한 이해가 필요해 보입니다.

첫 번째 포스팅에서는 이더리움을 비롯하여 블록체인 자체에 대한 정의를 하였다. 본 포스팅을 포함하여 두 개의 포스팅을 통해서 이더리움 프로토콜에서 다루게 될 8가지 주제들을 간단하게 소개하도록 하겠다.

1. Accounts

글로벌하게 공유되는 이더리움의 state는 account라는 작은 객체들로 구성되는데 이는 메시지 전달 프레임워크를 통해서 다른 account들과 상호작용한다. 각 각의 account들은 자기 자신에 대한 정보와 20바이트 주소를 가지며 이더리움은 160bit의 주소를 통해서 각 account들을 식별한다. 이 때, account에는 두 가지 종류가 있다.

(1) Externally owned account : 개인 키로 제어되는 것으로서 코드를 저장할 수 없다.

(2) Contract account : contract 코드에 의해 제어되며 코드를 저장할 수 있다.

EOA vs CA

Externally Owned Accounts vs. Contract Accounts

두 account의 기본적인 차이에 대해서 이해하는 것은 매우 중요하다. Externally owned account는 다른 externally owned account에 메시지를 보내거나 다른 contract account에 메시지를 보낼 수 있으며, 이를 위해서 해당 account의 개인키를 사용하여 트랜잭션을 생성하고 서명한다. 두 개의 externally owned account 사이에서의 메시지는 단순하게 이더만을 전송한다(송금). 그러나 externally owned account에서 contract account으로의 메시지는 contract account의 코드를 활성화시키고, 다양한 기능을 활성화시킨다(토큰 전송, 내부 저장소에 작성, 새로운 토큰 mint, 계산 수행, 새로운 contract 생성 등).

Externally owned account와 달리 contract account는 스스로 새로운 트랜잭션을 개시할 수 없다. 대신에 contract account는 다른 트랜잭션들(externally owned account이나 다른 contract account으로부터 받은)에 대한 응답으로 트랜잭션을 실행할 수 있다. 우리는 contract에서 contract를 불러오는 것들에 대해서 트랜잭션과 메시지 섹션에서 자세히 배울 것이다.

그러므로 이더리움 블록체인의 모든 기능은 항상 externally owned account의 트랜잭션으로부터 시작된다.

Account state

account는 그 종류와 관계 없이 4개의 요소로 구성된다.

(1) Nonce : externally owned account의 경우, 이 숫자는 해당 account의 주소로부터 보내진 트랜잭션들의 숫자를 의미한다. contract account의 경우, 이 값은 account에 의해 생성된 contract의 숫자를 의미한다.

(2) balance : 이 account가 소유하고 있는 Wei의 양이다(1이더 = 1e+18 wei).

(3) storageRoot : 머클 패트리시아 트리의 루트 노드의 해시값이다. 이 트리는 account의 저장된 요소들의 해시값을 암호화하는데, 초기값은 비어 있다.

(4) CodeHash : 이 account의 EVM(Ethereum Virtual Machine) 코드의 해시값으로 contract account에서는 실행시킬 코드의 해시값이고, externally owned account에서는 비어 있는 문자열의 해시값이다(externally owned account에서는 코드를 저장할 수 없다).

2. World state

이더리움의 global state는 account의 주소와 account사이의 mapping으로 구성된다. 이러한 mapping은 머클 패트리시아 트리라고 알려져 있는 자료 구조로 저장된다.

이더리움에서는 key/value mapping이 주소와 연관된 account(각 account의 4가지 구성요소를 포함하여) 사이에서 이루어진다.

그리고 이더리움 블록 헤더는 다음과 같은 세 종류의 머클 트리의 루트노드 해시값을 갖는다.

- state trie : 해당 블록을 통해서 변경된 account 정보를 가진다.

- transaction trie : 현재 block의 transaction 정보를 가진다.

- receipts trie : 현재 block의 receipt(거래 영수증) 정보를 가진다.

머클 트리의 모든 정보를 효과적으로 저장하는 능력은 이더리움에서도 특히 light client 또는 light node라고 불리는 노드에 대해서 매우 유용하다. 보편적으로 말하자면, 이더리움에는 full node와 light node 두 가지 종류의 노드가 있다.

full archive node는 제네시스 블록부터 현재 블록까지 전체 체인을 다운 받고 포함된 모든 트랜잭션을 실행시킨다. 전형적으로 채굴자는 full archive 노드를 저장한다. 또한 모든 트랜잭션을 실행시킬 필요 없이 full node를 다운받을 수도 있는데, 이 경우에도 전체 체인을 포함하고 있어야 한다.

그러나 모든 트랜잭션을 실행시킬 필요가 없거나 쉽게 과거의 데이터를 query할 수 있는 경우에는 전체 체인을 저장할 필요가 없다. 이것이 바로 light node이다. 전체 체인을 다운받고 저장하고 모든 트랜잭션을 실행시키는 것 대신에 light 노드들은 트랜잭션들을 실행하거나 관련된 state들을 가져오지 않은 채 전체 체인의 블록 헤더만을 다운받는다. 블록 헤더에는 세 가지 종류의 트리 데이터들의 해시값이 저장되어 있기 때문에 light node는 트랜잭션, 이벤트, 잔금 등에 대해서 입증 가능한 답변을 생성하고 받을 수 있다.

이것이 가능한 이유는 해시값이 리프 노드(이는 트리에서의 노드를 의미한다)에서 위의 노드들로 전파되어 가는 머클 트리의 구조 덕분이다. 만약에 악의적인 사용자가 머클 트리의 bottom에 가짜 트랜잭션으로 바꿔 넣으려고 시도를 한다면, 이러한 변화는 위의 노드들의 해시값에서 변화를 일으킬 것이고, 결국 트리의 루트까지 바뀌게 되고 이를 통해 위,변조를 감지할 수 있다.

Merkle Proof는 머클트리에 존재하는 데이터가 올바른 데이터인지 입증하는 절차이다. Merkle proof에는 다음값들이 필요하다.

(1) 증명하려는 데이터와 그것의 해시값

(2) 머클트리의 루트 해시값

(3) branch(데이터에 해당하는 리프노드에서 루트노드까지의 경로 노드들을 계산하는데 필요한 해시값들 이며 아래 그림에서 3번을 비롯하여 초록색 부분들이 이에 해당한다)

데이터의 해시값과 branch 해시값들을 이용해 경로에 해당하는 노드들의 해시값을 구할 수 있고, 이를 반복해 루트 노드의 해시값을 구할 수 있다. 구한 루트노드의 해시값과 기존에 알고 있던 루트노드의 해시값이 같다면 검증한 데이터가 올바른 데이터임을 입증 할 수 있다.

요약하면, Merkle patricia 트리는 루트 노드가 트리에 저장되어 있는 데이터에 암호학적으로 의존하는 형태이고, 따라서 루트의 해시값은 데이터의 안전한 id로 사용될 수 있다. 블록 헤더는 state, transaction 그리고 receipts 트리의 루트 해시값을 포함하기 때문에 어떤 노드라도 매우 큰 크기의 전체 Global state를 저장할 필요 없이 이더리움의 state 일부를 입증할 수 있다.

3. Gas and Payment

이더리움에서 매우 중요한 것 중 하나는 수수료이다. 이더리움에서의 트랜잭션의 결과로서 발생하는 모든 연산은 수수료를 발생시키는데, 이 때 수수료는 gas라고 불리는 것을 통해 지불된다.

Gas는 특정한 연산에 대해 필요한 수수료를 측정하는데 사용되는 단위이다. Gas price는 가스 당 지불하려고 생각하는 ether의 양을 의미하며, gwei라는 단위를 사용한다. wei는 ether에서 가장 작은 단위이며, 1 ether는 10¹⁸ wei를 뜻하고, gwei는 10⁹ wei를 의미한다.

모든 트랜잭션에서 송신자는 gas limit과 gas price를 설정한다. 이는 트랜잭션을 실행시키면서 지불할 의사가 있는 wei의 최대치를 의미한다.

예를 들면, 송신자가 gas limit을 50,000 그리고 gas price를 20 gwei를 설정했다고 하자. 이는 송신자가 최대 50,000 * 20 gwei인 1,000,000,000,000,000 wei(0.001 ether)를 트랜잭션 실행에 사용하고 싶다는 것을 의미한다.

gas limit은 송신자가 지불하길 바라는 최대의 가스라는 것을 기억하자. 만약에 이 최대치를 지불하고도 남을 충분한 양의 ether를 그들의 account에 가지고 있다면, 트랜잭션이 잘 이루어질 것이다. 트랜잭션이 끝나고 나서 송신자는 사용되지 않은 가스에 대해서 환불 받고 이는 기존의 비율로 교환된다.

송신자가 트랜잭션을 수행하기에 충분한 양의 가스를 제공하지 못할 경우 트랜잭션은 out of gas(가스 부족)를 실행하고 해당 트랜잭션은 유효하지 않은 것으로 고려된다. 이 경우에는 트랜잭션 처리가 멈추고 트랜잭션 발생 이전의 state로 돌아간다.

게다가 어떤 트랜잭션인지 어디서 수행했는지 같은 트랜잭션에 대한 기록도 남지 않는다. 뿐만 아니라 machine은 가스가 바닥나기 전까지 이미 연산에 대해서 동작을 하였기 때문에 송신자에게 어떠한 가스도 환불되지 않는다.

그러면 이 가스는 정확히 어디로 가는가? 모든 가스에 대한 돈은 채굴자의 account 주소인 beneficiary 주소로 보내 진다. 채굴자는 연산을 수행하고 트랜잭션을 입증하는 노력을 하였기 때문에 보상으로서 그 수수료를 가져가는 것이다.

전형적으로 가스 가격이 높을수록 트랜잭션에서 채굴자가 얻는 이득이 커지기 때문에 채굴자는 더 큰 수수료를 얻을 수 있는 트랜잭션을 선택할 것이다. 이런 방식으로 채굴자들은 그들이 입증하거나 무시할 트랜잭션들을 자유롭게 선택한다. 어느 정도의 가스 가격이 필요한지 송신자들에게 안내하기 위해서 채굴자들은 그들이 트랜잭션을 선택할 최소한의 가스 가격을 홍보할 선택권 또한 가지고 있다.

Storage를 위한 수수료

가스는 연산 단계에서만 지불하는 것이 아니라 storage 사용 시에도 지불해야 한다. 저장을 위한 총 수수료는 32바이트 단위에 비례하여 지불된다.

저장 수수료는 미묘한 양상을 띤다. 예를 들어, 증가된 storage는 모든 노드에 대해서 이더리움 state 데이터베이스의 크기를 증가시키기 때문에, 저장될 데이터의 양을 적게 유지하는 것에 대한 인센티브가 있다. 좀 더 알아보자면, 새로운 변수를 storage에 할당할 경우 20,000gas가 소모되고, 기존 변수를 변화시키는 경우에는 5,000gas가 필요된다. 그리고 storage를 비우는 것은 기존의 변수값을 0으로 만드는 것으로 동작하는데, 이 경우 0으로 변경하는데 5,000gas가 소모되고, 처음 할당할 때 들었던 20,000gas를 돌려 받는다. 따라서 15,000gas를 돌려 받게 된다.

수수료의 목적이 무엇인가?

이더리움이 동작하는 방식의 중요한 한가지 양상은 네트워크에 의해서 실행되는 모든 하나의 오퍼레이션은 모든 full 노드에 의해 동시에 효력이 발생해야 한다. 그러나 EVM의 연산 단계는 매우 비싸기 때문에, 이더리움 스마트 contract은 파일 저장, 이메일, 또는 머신러닝처럼 네트워크에 긴장을 야기하는 복잡한 사용보다는 단순히 로직을 실행하거나 서명을 증명하고 다른 암호학적 개체를 입증하는 단순한 업무를 하는데 사용하는 것이 좋다. 따라서 수수료를 부과하는 것은 사용자들이 네트워크에 과부하를 거는 것을 방지하기 휘함이라고 할 수 있다.

게다가 이더리움(솔리디티)은 튜링 완전 언어이다(즉 튜링 machine은 어떠한 컴퓨터 알고리즘에 대해서도 동작할 수 있다). 따라서 반복문을 허용하고 있으며, 이로 인해 이더리움은 halting problem(프로그램이 무한하게 실행될지 말지를 결정할 수 없는 문제)에 취약하다. 만약에 수수료가 없다면, 악의적인 공격자가 무한 루프를 트랜잭션 내부에 실행함으로써 아무런 처벌 없이 네트워크를 파괴시키기 쉽다. 따라서 수수료는 네트워크가 이러한 고의성 공격으로부터 이더리움을 방어하는 역할을 수행한다.

4. 트랜잭션과 메시지

우리는 초기에 이더리움이 트랜잭션을 기반으로 하는 state machine임을 주목했다. 즉 다른 account 사이에서 일어나는 트랜잭션들은 이더리움의 global state를 바꾼다.

가장 기본적으로, 트랜잭션은 암호학적으로 서명된 지시서이다. 이는 externally owned account에 의해 발생하고 정렬된 후 블록체인으로 제출된다(블록 단위로 묶여서).

여기에는 두 종류의 트랜잭션이 존재한다:

i) contract 생성(새로운 이더리움 contract을 생성하는 트랜잭션)

ii) 메시지 호출 (Message Call)

그리고 모든 트랜잭션은 종류의 상관 없이 다음의 요소를 포함한다.

1. nonce : 송신자에 의해 보내진 트랜잭션의 개수

2. gasPrice : 트랜잭션이 실행될 때 송신자가 지불할 의사가 있는 가스의 단위를 Wei로 표현한 값

3. gasLimit : 송신자가 이 트랜잭션이 실행될 때 지불할 의사가 있는 가스의 양. 이는 어떠한 연산이 실행되기 전에 설정되고 미리 지불된다.

4. to : 수령자의 주소. contract 생성 트랜잭션의 경우, contract account의 주소가 아직 존재하지 않기 때문에 empty값이 사용된다.

5. value : 송신자에서 수령자로 전송되는 wei의 양. contract 생성 트랜잭션의 경우, 이 값은 새롭게 생성된 contract account의 초기 잔금의 역할을 수행한다.

6. v, r, s : 트랜잭션의 송신자를 식별할 서명을 발생시키는데 사용되는 변수

7. init(contract account에서만 존재) : 새로운 contract account을 시작하는데 사용되는 EVM코드 조각. init은 오직 한번만 수행되고 버려진다. 처음 init이 수행될 때 이는 account code의 body를 호출하는데 이는 contract account과 연관되어 있는 code 조각이다.

8. data(메시지 콜에서만 존재하는 선택 영역) : 메시지 콜의 입력 데이터(인자들).

예를 들어 만약에 스마트 contract이 domain 등록 서비스를 수행한다면, 그 contract의 메시지 콜은 아마 domain과 ip 주소와 같은 입력 값이 될 것이다.

우리는 메시지 호출과 contract 생성 트랜잭션이라는 두 가지의 트랜잭션이 항상 externally owned account에 의해 개시되고 블록체인에 제출됨을 배웠다. 이 외에도 트랜잭션에 대해서 또 하나 생각해 볼 점은 트랜잭션이 이더리움 내부 state와 외부 세계를 연결한다는 것이다.

이는 contract들이 다른 contract들과 소통할 수 없음을 의미하는 것이 아니다. global한 관점에서 이더리움의 state 내 존재하는 contract들은 같은 범위에 존재하는 contract들과 소통할 수 있다. 이것은 “메시지” 또는 다른 contract들로의 “내부 트랜잭션”을 통해서 수행된다. 우리는 메시지와 내부 트랜잭션들을 트랜잭션과 비슷한 것으로 생각할 수 있다. 그러나 가장 큰 차이는 메세지들은 externally owned account에서 생성될 수 없다는 점이다. 대신에 이것들은 contract에 의해서 생성되고, 트랜잭션과 달리 오직 이더리움 실행 환경에서만 존재하는 가상의 개체로서 정렬(serialized)될 수 없다.

하나의 contract가 내부 트랜잭션을 다른 contract으로 보낼 때, 이를 받는 contract account에서 이와 관련 코드를 실행한다.

하나의 주목할 점은 내부 트랜잭션 또는 메시지들은 gasLimit을 포함하지 않는다는 것이다. 이는 gas limit이 본래의 트랜잭션의 외부 생성자에 의해서 결정되기 때문이다(몇 몇 externally owned account에 의해서). externally owned account이 설정한 gas limit은 contract과 contract 간의 메시지처럼 트랜잭션의 결과로 발생하는 것들까지 모두 수행하기에 충분해야 한다. 만약 트랜잭션과 메시지 연결에서 특정한 메시지 실행이 gas를 다 소모해 버린다면, 메시지 실행은 취소될 것이고 실행에 의해 유발된 이 후의 메시지들 역시 취소될 것이다. 그러나 parent execution(메시지를 호출한 트랜잭션)까지 반환될 필요는 없다.

반응형