비트코인과 이더리움 블록 비교

비트코인의 블록은 헤더와 바디로 나누어 볼 수 있습니다. 이더리움도 비트코인의 블록구조와 크게 다르진 않지만 블록의 헤더부분에 uncle_list와 stack_trace 라는 값이 추가되어 있는 형태입니다.


  • uncle list: 비트코인의 이전블록을 이더리움에서 parent 블록이라고 말하기 때문에 생긴 용어. stale 블록을 uncle 블록이라 칭함 (자세한 설명은 아래에서)

비트코인과 이더리움 블록헤더 비교


비트코인이더리움
블록해시hashstate_root
이전 블록해시prev_lbockparent_hash
거래관련된 루트해시mrkl_root

TRIEHASH(transaction_list)

TRIEHASH(uncle_list)

TRIEHASH(stack_trace)

난이도bitsdifficulty
타임스탬프timetimestamp
넌스noncenonce
그외 데이터

size

ver

n_tx

extra_data

(block) numbber

coinbase address (채굴주소)

.... 등등

비트코인과 블록헤더의 구조는 거의 유사하나 블록해시를 구할 때, 몇 가지 항목이 더 추가됨

  • uncle_list, stack_trace, extra_data 등등

이더리움 블록 구성

위에서 비트코인과 간략하게 비교했으니 이제 이더리움만 자세하게 파봅시다.



https://etherscan.io/block/5529581 해당 주소에서 이더리움의 블록정보를 확인한 정보입니다.


이더리움의 코드(GO)를 보면 아래와 같이 블록과 블록헤더가 struct로 선언되어 있습니다.

블록

// Block represents an entire block in the Ethereum blockchain.
type Block struct {
	header       *Header
	uncles       []*Header
	transactions Transactions
	// caches
	hash atomic.Value
	size atomic.Value
	// Td is used by package core to store the total difficulty
	// of the chain up to and including the block.
	td *big.Int
	// These fields are used by package eth to track
	// inter-peer block relay.
	ReceivedAt   time.Time
	ReceivedFrom interface{}
}

블록헤더

// Header represents a block header in the Ethereum blockchain.
type Header struct {
	ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"`
	UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"`
	Coinbase    common.Address `json:"miner"            gencodec:"required"`
	Root        common.Hash    `json:"stateRoot"        gencodec:"required"`
	TxHash      common.Hash    `json:"transactionsRoot" gencodec:"required"`
	ReceiptHash common.Hash    `json:"receiptsRoot"     gencodec:"required"`
	Bloom       Bloom          `json:"logsBloom"        gencodec:"required"`
	Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"`
	Number      *big.Int       `json:"number"           gencodec:"required"`
	GasLimit    uint64         `json:"gasLimit"         gencodec:"required"`
	GasUsed     uint64         `json:"gasUsed"          gencodec:"required"`
	Time        *big.Int       `json:"timestamp"        gencodec:"required"`
	Extra       []byte         `json:"extraData"        gencodec:"required"`
	MixDigest   common.Hash    `json:"mixHash"          gencodec:"required"`
	Nonce       BlockNonce     `json:"nonce"            gencodec:"required"`
}

블록헤더 설명

  • ParentHash : 부모 블록의 해시값
  • UncleHash : 현재 블록의 엉클 블록들의 해시값
  • Coinbase : 채굴 후 해당 트랜잭션의 수수료를 받을 계정 주소
  • Root: 계정의 상태정보가 모여있는 머클 패트리시아 트리의 루트 노드 해시값
  • TxHash: 블록의 모든 트랜잭션에 대한 머클트리의 루트노드 해시값
  • ReceiptHash: 블록 내 모든 트랜잭션에 대한 receipt들의 머클트리의 루트노드 해시값
  • Bloom: 로그 정보를 사용하는데 사용하는 32바이트 블룸필터
  • Difficulty: 블록 난이도로 이전블록의 난이도와 타임스탬프로 계산
  • Number : 현재 블록번호
  • GasLimit: 블록당 지급가능한 최대 가스 총합
  • GasUsed: 블록내 트랜잭션에 사용된 가스의 총합
  • Time : 블록의 최초 생성시간
  • Extra : 블록의 기타정보
  • MixDigestNonce : 작업증명에서 해시값을 계산하는데 충분한 계산횟수를 보장하기 위해 사용하는 값


Root, TxHash, ReceiptHash는 머클트리의 각 노드를 해시한 최종 루트해시값에 해당하고 나머지 값들은 각각 하나의 상수로 볼수 있습니다.


제네시스 블록

제네시스 블록은 블록의 첫번째에 위치하는 최초 블록을 말하며 블록번호 0번에 해당되고 어떤 트랜잭션도 포함되지 않습니다.

// Genesis specifies the header fields, state of a genesis block. It also defines hard
// fork switch-over blocks through the chain configuration.
type Genesis struct {
	Config     *params.ChainConfig `json:"config"`
	Nonce      uint64              `json:"nonce"`
	Timestamp  uint64              `json:"timestamp"`
	ExtraData  []byte              `json:"extraData"`
	GasLimit   uint64              `json:"gasLimit"   gencodec:"required"`
	Difficulty *big.Int            `json:"difficulty" gencodec:"required"`
	Mixhash    common.Hash         `json:"mixHash"`
	Coinbase   common.Address      `json:"coinbase"`
	Alloc      GenesisAlloc        `json:"alloc"      gencodec:"required"`
	// These fields are used for consensus tests. Please don't use them
	// in actual genesis blocks.
	Number     uint64      `json:"number"`
	GasUsed    uint64      `json:"gasUsed"`
	ParentHash common.Hash `json:"parentHash"`
}

제네시스 블록 설명

  • Alloc : 일정량의 이더를 초기 계정에 할당할때 사용하는 값으로 채굴작업 없이 초기 일정량의 이더를 발생하여 ICO를 통해 판매하는데 사용할수 있음
  • Coinbase : 채굴 후 보상코인을 수령할 주소인데 제네시스 블록에서는 채굴이 일어나지 않기에 어떠한 값을 할당해도 상관없음
  • Nonce : mixhash와 함께 채굴 시에 사용되는 값, 8바이트
  • Mixhash : Nonce와 함께 채굴 시에 사용되는 값, 32바이트
  • Difficulty : 채굴시의 목표값
  • ExtraData : 32바이트 옵션항목
  • GasLimit : 블록의 최대 가스량
  • ParentHash : 이전 부모블록의 해시값, 제네시스블록은 부모가 없기 때문에 0으로 할당
  • TimeStamp : 블록의 생성시간

이더리움 블록체인과 채굴

비트코인: 거래(이체) 데이터 저장방식 (거래정보만 블록에 저장)

이더리움: 계정 데이터 저장방식 (모든 계정정보를 저장)

  • 계정의 balance등의 정보를 직접변경
  • patricia tree를 사용하여 저장 데이터의 용량을 줄임


위와 같이 이더리움 블록체인은 비트코인과 유사하나 다른점이 존재합니다. 비트코인과는 달리 이더리움 블록은 transaction list와 가장 최근의 상태(state) 복사본을 가지고 있다는 것입니다. 이외에도 블록의 넘버와 difficulty 또한 블록 내에 저장됩니다. 기본적인 이더리움 블록 검증 알고리즘은 아래와 같습니다.


  1. 참조하고 있는 이전 블록이 존재하는지와 유효한지 확인
  2. 현재 블록의 타임스탬프가 참조하고 있는 이전 블록의 타임스탬프보다 크고 현 시점을 기준으로 15분 후보다 작은 값인지 확인
  3. 블록 넘버, difficulty, 트랜잭션 루트, uncle 루트, gas limit등이 유효한지 확인
  4. 블록에 포함된 작업 증명이 유효한지 확인
  5. 위 그림의 S[0] 이 이전 블록의 마지막 상태(state)라고 가정
    1. TX를 현재 블록의 n개의 트랜잭션 리스트라고 가정하고 0 부터 n-1에 대해, S[i+1] = APPLY(S[i], TX[i]) 로 설정했을 때, 어플리케이션이 오류를 반환하거나, 이 시점까지 블록에서 소모된 총 gas가 GASLIMIT를 초과하면 오류를 반환
  6. 채굴자에게 지불된 보상 블록을 S[n] 덧붙인 후 이것을 S_FINAL 이라 가정
    1. 상태 S_FINAL의 머클 트리 루트가 블록 헤더가 가지고 있는 최종 상태 루트와 같은지를 검증. 이 값이 같으면 그 블록은 유효한 블록이고 다르면 유효하지 않은 것으로 판단

이러한 접근은 모든 상태를 각 블록에 저장할 필요성 때문에 매우 비효율적인 것처럼 보이지만, 실제로는 효율성의 측면에서는 비트코인과 비교할만 합니다. 그 이유는 상태가 트리 구조로 저장되고, 모든 블록 후에 단지 트리의 작은 부분만이 변경되기 때문입니다. 보통 인접한 두 개의 블록간에는 트리의 대부분의 내용이 같아서 한번 데이터가 저장되면 포인터(서브트리의 해쉬)를 사용하여 참조될 수 있기 때문입니다. 패트리시아 트리(Patricia tree)로 알려진 이러한 종류의 특별한 트리는 머클 트리 개념을 수정하여 노드를 수정할 뿐만 아니라, 효율적으로 삽입되거나 삭제하여 이러한 작업을 수행할 수 있도록 해줍니다. 또한, 모든 상태 정보가 마지막 블록에 포함되어 있기 때문에, 전체 블록체인 히스토리를 모두 저장할 필요가 없어지게 됩니다. 이러한 방법으로 비트코인에 적용된 기술과 비교하면 5~20배의 저장 공간 절약의 효과가 생깁니다.

물리적인 하드웨어 관점에서 볼 때, 컨트랙트 코드는 “어디에서" 실행되는가 하는 의문이 쉽게 들 수 있습니다. 컨트랙트 코드를 실행하는 프로세스는 상태 전환 함수 정의의 한 부분이고, 이것은 블록 검증 알고리즘의 부분이므로, 트랜잭션이 블록 B에 포함되면 그 트랜잭션에 의해 발생할 코드의 실행은 블록 B를 다운로드 하고 검증하는 모든 노드들에 의해 실행됩니다.

엉클블록

동시에 블록이 생성되어 전파되는경우 블록의 유효성 검증은 통과되었지만, 블록의 난이도가 상대적으로 낮아 블록으로 채택되지못한 블록을 엉클블록이라고 합니다. 엉클블록이 많아지만 다음과 같은 문제가 발생합니다.

  1.  엉클블록에 포함된 트랜잭션은 처리가 되지않기 때문에 트랜잭션처리의 지연문제가 발생
  2. 엉클블록은 체인에 연결되지않기 때문에 엉클블록을 발견하는데 사용된 컴퓨팅파워가 낭비되는 문제가 발생
  3. 엉클블록이 생성된 후 다음 블록이 생성되면 평균 블록 생성시간이 늘어나 블록생성 난이도가 낮아지기 때문에 네트워크 보안수준을 떨어뜨리게 됨

이더리움은 이러한 문제를 고스트 알고리즘을 사용하여 해결하였습니다. 고스트 알고리즘은 다음 번에 설명하겠습니다.


BST에서 위와 같은 Skewed Tree의 경우 복잡도가 O(n)이 나오는 한계점을 해결하기 위해 AVL Tree가 고안됨. AVL 은 해당 자료구조를 만든 사람의 앞글자를 하나씩 따서 만든 것(..)

AVL Tree 예시

AVL Tree

Not AVL Tree

용어

  • 노드의 height: h
  • balance factor: bf (왼쪽 서브트리의 height - 오른쪽 서브트리의 hegiht)
  • empty height: -1

특징

  • AVL 트리는 BST이면서 동시에 균형을 유지하고 있음
  • 모든 노드의 왼쪽과 오른쪽 서브트리의 높이 차이가 1 이하 (왼쪽과 오른쪽 서브트리의 height 계산 결과가 1, 0, -1 이외라면 해당 트리는 AVL 트리가 아님 - 만약 height가 없는 경우는 -1)
    • 즉, 모든 노드들은 balance factor 를 알고 있음
  • 균형을 유지하고 있기 때문에 이진 검색 시의 효율성을 보장

문제는 이러한 균형을 맞추려 하다 보니 유지하는 방법이 복잡함. 예를 들어, 노드 삽입이나 삭제로 인해 왼쪽과 오른쪽 서브트리의 height의 계산결과가 2, -2가 나온 경우, 트리를 rotation 시켜줘야 함


rotation에는 2가지 관점이 있는데 AVL 트리를 height balance로 유지하는 것과 binary search tree로 유지하는 관점이 있음. 관점은 나뉘어 있지만 가장 중요한 것은 rotation 시키면서 트리의 height를 낮춰야 복잡도가 줄어듦

rotation의 방법은 4가지로 1번만 rotation 시키는 LL, RR와 2번 rotation 시키는 LR, RL이 존재.


Single Rotation

LL (Right)


왼쪽은 차이가 2이고 오른쪽은 0이므로 왼쪽이 무너진 경우. 이 경우는 오른쪽으로 트리를 회전시켜주면 해결

RR (Left)


왼쪽은 차이가 0이고 오른쪽은 2이므로 오른쪽이 무너진 경우. 이 경우는 왼쪽쪽으로 트리를 회전시켜주면 해결

Double Rotation

위에서 본 LL, RR과는 달리 방향이 일정하지가 않기 때문에 첫 회전에서는 LL 또는 RR로 방향을 맞춘 다음 다시 회전시켜 높이의 균형을 유지시켜줌

RL (Right & Left)


가장 마지막 노드인 422 값을 부모노드와 자리를 바꾸면 바로 RR의 형태를 이루기 때문에 자리를 바꾼 후, RR 로 회전을 한번 더 시킴.

LR(Left & Right)

가장 마지막 노드인 422 값을 부모노드와 자리를 바꾸면 바로 LL의 형태를 이루기 때문에 자리를 바꾼 후, LL 로 회전을 한번 더 시킴.

장단점

  • 검색, 삽입, 삭제 모두 O(logN)이며 항상 균형을 맞춤
  • 프로그래밍하기가 어렵고 디버깅 또한 어려움.
  • 위 검색, 삽입, 삭제가 빠르긴 하지만 균형을 맞추는데에 시간이 듦
  • 대규모 tree를 이룬 후 검색하는 것은 DB에서 주로 발생하는데 DB는 이미 B-Tree 자료구조를 사용 중임


'공부 > 자료구조' 카테고리의 다른 글

AVL Tree  (0) 2018.08.17
Binary Search Tree  (0) 2018.08.15
Heap  (0) 2018.08.13
Binary Tree  (0) 2018.08.01
Tree  (0) 2018.07.31
Stack, Queue, Circular Queue  (0) 2018.07.30

Binary Search Tree(BST - 이진검색트리) 는 비어있거나 아래의 속성을 만족하는 binary tree 입니다. 자세하게 Binary Search (이진 검색)과 Linked List를 결합한 자료구조입니다. 이진 검색의 검색능력을 유지하면서 빈번한 값의 삽입, 삭제가 가능하도록 고안되었습니다. 이진검색의 경우 검색에 소요되는 시간복잡도는 O(log₂n)으로 빠르지만 자료 입력, 삭제가 불가능합니다. linked list의 경우 자료 입력, 삭제에 필요한 시간복잡도는 O(1)로 효율적이지만 탐색하는 데에는 O(n)의 복잡도가 발생합니다.

정의

  1. 각각의 모든 node 들의 key는 중복된 값이 아님 (unique)
  2. 기존의 binary tree는 순서가 없지만 BST는 순서가 존재
  3. parent node의 왼쪽은 부모보다 작은 값이고 오른쪽은 부모보다 큰 값임
  4. 왼쪽, 오른쪽의 서브 트리또한 BST임

Search

  1. 찾고자 하는 Key와 root node값이 같으면 성공
  2. Key가 root node 값보다 작다면 (key < root node) 왼쪽의 sub tree로 이동
  3. Key가 root node 값보다 작다면 (key > root node) 오른쪽의 sub tree로 이동
  4. 1~3번 반복
  5. 만약 조건에 맞는 데이터가 없으면 실패 (tree에 값이 존재하지 않는 경우)


위 그림에서 120 값을 찾는 예시입니다. 

  1.  root node(=100)와 찾고자 하는 값 (=120) 비교
  2. root node보다 찾고자 하는 값이 더 크므로 (100 < 120) 오른쪽 subtree로 이동
  3. 오른쪽 subtree의 노드값(=150)과 찾고자 하는 값(=120)과 비교
  4. 찾고자 하는 값이 더 작으므로 (150 > 120) 왼쪽 subtree로 이동
  5. 120값이므로 검색 성공


Insert

값을 삽입하고자 하거나 찾고자 하는 값이 없을 경우 루트노드에서 시작, 값을 비교해가면서 tree의 가장 마지막까지 간 다음 값을 입력

예시

위 그림에서 80을 넣고자 하면 아래와 같은 위치에 삽입


Delete

  1. 첫 단계는 지우고자 하는 값이 해당 tree에 있는지 search
  2. 지우고자 하는 값이 leaft node(가장 마지막)에 위치해있으면, 그냥 지우면 됨
  3. internal node라면 다음과 같이 분기가 됨
    1. 지워야 하는 node가 child node를 1개 가지고 있는 경우, internal node를 지운 후 해당자리에 child node를 옮김
    2. 지워야 하는 node가 child node를 2개 가지고 있는 경우, 왼쪽의 subtree에서 가증 큰 노드 또는 오른쪽 subtree에서 가장 작은 노드를 옮김

예시

50 (leaf node) 삭제


75 (internal node 이며 1개의 child node 존재) 삭제


150 (internal node 이며 2 child node 존재) 삭제

1. 왼쪽의 subtree에서 가장 큰 노드를 이동


2. 오른쪽 subtree에서 가장 작은 노드를 이동



internal node이며 child node를 2개 가지고 있는 경우 삭제하는 방법은 2가지가 있지만 여기서 조건적으로 효율적인 방법이 존재.

1, 2번의 방법 중 트리의 height를 줄일 수 있는 방법을 채택하는 것이 향후 트리 검색의 속도를 향상시킬 수 있음

복잡도

BST는 검색, 삽입, 삭제 모두 O(h)임. h는 BST의 높이(height)

BST에서는 inorder(LVR) 검색 방식을 사용

BST는 평균(최상) 시간복잡도가 O(log₂n)이지만 최악의 경우 O(n)임. (skewed tree이면 node의 수만큼 시간이 소요됨)

  • tree가 complete binary tree거나 full binary tree이면 O(log₂n), skewed tree이면 O(n)

위 O(N)의 경우때문에 노드가 얼마 되지 않아도 검색속도가 나오지 않을 가능성이 존재함. 이 때문에 AVL Tree가 고안됨


'공부 > 자료구조' 카테고리의 다른 글

AVL Tree  (0) 2018.08.17
Binary Search Tree  (0) 2018.08.15
Heap  (0) 2018.08.13
Binary Tree  (0) 2018.08.01
Tree  (0) 2018.07.31
Stack, Queue, Circular Queue  (0) 2018.07.30
  • Heap은 Complete Binary Tree를 기본으로 가지는 자료구조
  • 일반적으로 array로 구현하는 것이 좋음
  • Heap 은 최댓값 또는 최솟값을 찾아내는 연산을 빠르게 하기 위해 고안됨
  • 시간복잡도: O(log₂N)
  • Heap은 다음과 같은 속성(property)를 만족함
    • A가 B의 부모노드이면 A의 키값과 B의 키값 사이에는 대소관계가 성립
  • 종종 priority queue를 보충하는대에 사용

종류

max heap: root노드가 가장 큰 수

min heap: root노드가 가장 작은 수

Max Heap

부모노드의 키가 자식노드의 키보다 항상 큼


Node Insertion

max heap에서 노드 추가는 말단의 맨 오른쪽의 leaf node에 자리를 하나 만들고 해당 노드에 값을 대입한 다음 parent node와 값을 비교하며 자리를 바꿔 나감. (root node 까지)

Node Deletion

max heap에서 노드 삭제는 항상 루트노드를 지움. 그 다음 complete binary tree를 유지하기 위해 tree를 재조정함. 말단의 맨 오른쪽 노드를 지운 다음, 루트 노드 자리에 옮기고 child node와 비교해 자리를 바꿔나감.


Max Heap에서 노드 추가, 삭제는 모두 트리의 depth만큼 걸림 -> O(log₂N)

Min Heap

부모노드의 키가 자식노드의 키보다 항상 작음



키의 대소관계는 오로지 부모노드와 자식노드 간에만 성립되며, 형제(sibling) 사이에는 대소관계가 정해지지 않음

Priority Queue

일반적인 queue는 FIFO 이기 때문에 먼저 들어온 데이터가 먼저 나가지만, priority queue는 우선순위가 높은 데이터 먼저 나감

새로운 노드가 삽입되면 우선순위에 맞는 위치에 삽입 (enqueue)

제거할 때는 우선순위가 가장 높은 맨 앞의 노드를 삭제 (dequeue)



'공부 > 자료구조' 카테고리의 다른 글

AVL Tree  (0) 2018.08.17
Binary Search Tree  (0) 2018.08.15
Heap  (0) 2018.08.13
Binary Tree  (0) 2018.08.01
Tree  (0) 2018.07.31
Stack, Queue, Circular Queue  (0) 2018.07.30



degree가 최대 2인 트리

i번째 level에 나올 수 있는 노드의 최대 개수는 2^(i - 1)

  • 주의 할 것은 전체 tree의 노드 최대 개수 또는 i번째 level까지 전체 노드의 개수가 아닌 i번째 level만 단독으로 보고 있음.

k가 tree의 depth일 때, 최대 노드의 개수는 : 2^k -1

위 그림에서 2번째 level의 노드의 최대 개수는 2^(2-1) = 2개이고, depth는 2^2-1 = 3개, height는 2^3 - 1 = 7개임


binary tree에는 skewed tree, complete binary tree, full(perfect) binary tree가 있음

Full (Perfect) Binary Tree

마지막 레벨까지 노드가 꽉 차게 있는 트리


Complete Binary Tree

노드가 왼쪽에서 오른쪽 순서로 순차적으로 존재하는 트리



위 그림에서 3번 노드가 없어도 complete binary node는 성립하지만 1번이나 2번 노드가 없으면 complete binary tree가 아니게 됨. 

Skewed Tree




binary tree를 구현하는 데엔 array로 구현하는 것이 좋지만 다른 트리에서는 효율성이 떨어지고 컴파일 언어에서 어레이 사이즈 제한때문에 저장공간 문제가 존재. C에서는 이를 linked list로 해결할 수 있음. (근데  linked list는 구현이 어려움)


Binary Tree Traversal

루트노드에서 시작해 linear 하게 노드를 1번씩 방문하는 방식은 아래와 같습니다.

V: 노드 방문

L: 왼쪽 branch를 타고 이동

R: 오른쪽 branch를 타고 이동


  • inorder: LVR (Left Visit Right)
  • preorder: VLR (Visit Left Right)
  • postorder: LRV (Left Right Visit)

예를 들어, preorder는 하위 트리를 탐색하기 전에 노드 방문이 완료

예시 (inorder: LVR)


  1. 루트노드인 X에서 시작.
  2. 왼쪽 브랜치가 있으므로 왼쪽 브랜치를 타고 Y 노드로 이동
  3. Y 노드에서도 왼쪽 브랜치가 있으므로 왼쪽 브랜치를 타고 S 노드로 이동
  4. S 노드에는 왼쪽 브랜치가 없어서 이동할 수 없음. 
  5. 왼쪽으로 이동할 수 없으므로 S 노드를 방문 후 오른쪽 브랜치로 이동하려하나 브랜치가 없어 Y노드로 롤백
  6. Y노드를 방문한 후 오른쪽 브랜치를 타고 이동하여 T 노드로 이동
  7. T노드는 4~5번과 동일.

위와 같은 순서로 값의 출력은 S, Y, T, X, Z 순으로 출력됨


위와 같이 binary tree의 모든 노드를 탐색하는 방법은 stack이 필요함. 

모든 노드를 탐색하는데에 걸리는 time complexity는 O(N)임 (N은 트리에 존재하는 노드의 개수)

'공부 > 자료구조' 카테고리의 다른 글

Binary Search Tree  (0) 2018.08.15
Heap  (0) 2018.08.13
Binary Tree  (0) 2018.08.01
Tree  (0) 2018.07.31
Stack, Queue, Circular Queue  (0) 2018.07.30
ADT, 복잡도(시간복잡도, 공간복잡도), 빅오 분석법  (0) 2018.07.29

상태변환함수



이더리움을 송금했다고 했을 때 계정의 상태가 어떻게 변하는지 아래에서 설명합니다.

상태변환 단계

  1. 트랜잭션이 형식에 제대로 맞는지(즉, 올바른 개수의 값을 가지고 있는지) 체크하고, 서명이 유효한지, nonce가 발신처 계정의 nonce와 일치하는지를 체크. 그렇지 않다면 오류를 반환
  2. gaslimit * gasprice  로 트랜잭션 수수료를 계산하고, 서명으로부터 발신처 주소를 결정
  3. 발신처 계정 잔고에서 위에서 구한 트랜잭션 수수료를 빼고 발신자 nonce를 증가. 발신처 잔고가 충분하지 않으면 오류를 반환
  4. GAS = gaslimit 으로 초기화 한 후, 트랜잭션에서 사용된 바이트에 대한 값을 지불하기 위해 바이트당 gas의 특정 양을 차감
  5. 발신처 계정에서 수신처 계정으로 트랜잭션 값을 보냄. 수신처 계정이 존재하지 않으면 새로 생성
  6. 수신처 계정이 컨트랙트면, 컨트랙트의 코드를 끝까지, 또는 GAS가 모두 소모될 때 까지 수행
  7. 발신처가 충분한 ‘돈'을 가지고 있지 못해서 값 전송이 실패하거나, 코드 수행시 GAS가 부족하면, 모든 상태 변경를 원상태로 돌려놓음. 단, 수수료(코드를 수행한 GAS)는 제외되고 이 수수료는 채굴자 계정에 더해지게 됨. 그 외에는, 모든 남아있는 모든 GAS에 대한 수수료를 발신처에게 돌려주고, 소모된 GAS에 지불된 수수료를 채굴자에게 보냄

상태변환 예제

아래와 같이 값을 가지고 있다고 가정하면 상태 변환 함수의 프로세스는 다음과 같습니다.

컨트랙트 계정의 storage는 0이라고 가정.

트랜잭션은 아래와 같이 필드를 가지고 전달된다고 가정

  • value = 10 ether
  • gaslimit = 2000
  • gasprice = 0.001ether
  • data = 64바이트(0-31 바이트까지는 숫자 2를 나타내고, 32-63 바이트는 CHARLIE 라는 문자열)

트랜잭션은 총 170바이트 길이를 가지고, 바이트당 GAS수수료는 5라고 가정

코드 실행 시, index 설정 작업의 GAS수수료는 187GAS로 가정


  1. 트랜잭션이 유효하고 형식이 제대로 맞는지 확인
  2. 트랜잭션 발송처가 최소 2000 * 0.001 = 2 ether를 가지고 있는지 확인하고 유효한 경우, 발송처의 계정에서 2ether를 차감
  3. GAS = 2000으로 초기화 한 후, 트랜잭션 처리 수수료인 850 GAS를 차감하면 1150 GAS가 남음
  4. 발송처 계정에서 보내고자 하는 10ether를 차감하고 이것을 컨트랙트 계정에 더함
  5. 코드(이미 작성되어 있는 컨트랙트 코드)를 실행. 이 경우는 간단한데, 컨트랙트의 index 2에 해당하는 스토리지가 사용되었는지 확인하고 (이 경우, 사용되지 않음) index 2에 해당하는 스토리지 값을 CHARLIE 로 설정. 이 작업을 하는 GAS 수수료를 차감하면, 남아있는 GAS의 양은 1150 - 187 = 963
  6. 963*0.001 = 0.963 ether를 송신처의 계좌로 되돌려주고, 결과상태를 반환


트랜잭션의 수신처에 컨트랙트가 없으면, 총 트랜잭션 수수료는 제공된 gasprice와 트랜잭션의 바이트 수를 곱한 값과 같아지고, 트랜잭션과 함께 보내진 데이터는 관련이 없어지게 됩니다. 즉, 위 예제를 사용하여 설명하면 수신처에 컨트랙트가 없으면 1150 GAS가 총 수수료이고 코드를 실행시킬 필요가 없기 때문에 187GAS 수수료를 사용하지 않게 됩니다.

메시지는 트랜잭션과 마찬가지 방식으로, 상태를 원래 상태로 되돌린다는 것에 주목해야 합니다. 메시지 실행시 GAS가 부족하게 되면 메시지 실행과 실행에 의해 발생된 다른 모든 실행들은 원래대로 되돌려지게 되지만, 그 부모 실행은 되돌려질 필요가 없습니다. 이것은 컨트랙트가 다른 컨트랙트를 호출하는 것은 안전하다는 것을 의미합니다. 예를 들어, A가 100 GAS를 가지고 B를 호출하면, A의 실행은 최대 100 GAS만 잃는다는 것을 보장받게 됩니다. 컨트랙트를 생성하는 CREATE라는 opcode를 보면, 실행 방식은 대체로 CALL과 유사하나, 실행 결과는 새로 생성된 컨트랙트의 코드를 결정한다는 차이가 있습니다.

코드 실행

코드 실행은 이미 작성되어 있는 컨트랙트의 코드를 실행하는 것입니다. 이미 예약되어 있는 작업을 실행하는 것으로 볼 수 있습니다.

이더리움 컨트랙트를 구성하는 코드는 이더리움 버추얼 머신 코드 또는 EVM 코드로 불리는 로우-레벨, 스택 기반의 바이트코드 언어로 작성됩니다. 이 코드는 연속된 바이트로 구성되어 있고, 각각의 바이트는 연산(operation)을 나타냅니다. 보통, 코드 실행은 0부터 시작하는 프로그램 카운터(pc)를 하나씩 증가 시키면서 반복적으로 연산을 수행하도록 구성된 무한 루프이고 코드의 마지막에 도달하거나 ERROR, STOP, RETURN 명령을 만나면 실행을 멈추게 됩니다. 연산을 수행하기 위해서는 아래 데이터를 저장하는 세가지 타입의 공간에 접근할 수 있어야 합니다.

  • 스택(stack): Last-In-First-Out(LIFO) 컨테이너(리스트형태)로 여기에 값들을 넣거나(push) 제거(pop) 할수 있음
  • 메모리(memory): 무한대로 확장 가능한 바이트 배열
  • 컨트랙트의 영속적인(long-term) 저장소(storage): 키/값 저장소 (key/value storage). 계산이 끝나면 사라지는 스택이나 메모리와는 달리 저장소는 영속적으로 유지

코드는 또한 블록 헤더의 데이터 뿐만 아니라 특정 값이나 발송자 및 수신되는 메시지의 데이터에 접근할 수 있고 계산하여 결과값을 데이터의 바이트 배열을 반환할 수도 있습니다.

EVM 코드의 공식 실행 모델은 단순한 구조로 되어 있습니다. EVM이 실행되는 동안 모든 계산 상태는 (block_state, transaction, message, code, memory, stack, pc, gas) 으로 튜플로 정의될 수 있고, block_state는 모든 계정을 포함하는 전역상태(global state)로서 잔고(value)와 저장소(storage)를 포함합니다. 무한 루프에 의해 반복되는 코드를 실행 할 때, code의 pc(프로그램 카운터)번째 바이트의 현재 명령이 실행되고(pc 가 코드의 길이보다 같거나 크면 pc는 0으로 초기화), 실행되는 각각의 명령은 튜플을 어떻게 변화시킬지에 대한 자신의 정의를 알고 있습니다. 예를 들어, ADD는 스택에서 두개의 아이템을 꺼내(pop), 그 합을 구한 후 다시 스택에 넣고(push) GAS를 1만큼 감소시키고, pc는 1 증가시킵니다. SSTORE 는 스택에서 두개의 아이템을 꺼내 이 아이템의 첫번째 값이 가리키는 컨트랙트 저장소 인덱스에 두번째 아이템을 넣습니다.

Tree 구조


트리는 위와 같은 구조를 갖고 있습니다.

용어

  • node: 트리에서 데이터를 의미
  • branch(link): 노드와 노드를 연결
  • root node: 최상위 노드
  • interior node: 자기자신 아래에 연결된 노드가 있는 형태
  • leaf node: 자기자신 아래에 노드가 더이상 연결되어있지 않은 형태
  • parent: child 노드들이 연결되어 있는 상위 노드
  • child: 부모노드 아래에 연결되어 있는 노드
  • sibling: 부모노드 아래에 존재하며 동일한 레벨에 있는 노드
  • degree (노드의 degree): 자기자신 아래에 연결된 노드가 몇개가 있는지
  • depth: 루트에서 어떤 노드에 도달하기까지 거쳐야 하는 branch(link)의 수
  • level: 트리의 특정 depth를 가지는 노드의 집합
  • height: 루트노드에서부터 가장 멀리 있는 노드의 depth
  • 트리의 degree: 트리의 최대 degree
    • 위 그림에서 노드의 최대 degree는 2

Skewed Tree (Degenerate Tree)


Full (Perfect) Tree


Binary Tree

degree가 최대 2 (0 <= degree <= 2)


Quad Tree

degree가 최대 4 (0 <= degree <= 4)


정의

  • root 노드를 제외한 모든 노드는 parent 노드를 1개만 가짐
  • leaf 노드를 제외한 모든 노드는 child 노드를 1개 이상을 가짐

Tree 자료구조의 다양한 타입

Binary Tree

  • Binary Search Tree, Heap, Digital Search Tree
  • Red-Black Tree, AA Tree, Splay Tree

Height-Balanced Binary Tree

  • AVL Tree, T-Tree

n-Way Tree

  • m-Way Tree
  • 2-3 Tree, 2-3-4 Tree

Height-Balanced m-Way Tree

  • B-Tree, B+-Tree, K-d B-Tree

Spatial Tree

  • Quad Tree, Oct Tree, R-Tree


'공부 > 자료구조' 카테고리의 다른 글

Binary Search Tree  (0) 2018.08.15
Heap  (0) 2018.08.13
Binary Tree  (0) 2018.08.01
Tree  (0) 2018.07.31
Stack, Queue, Circular Queue  (0) 2018.07.30
ADT, 복잡도(시간복잡도, 공간복잡도), 빅오 분석법  (0) 2018.07.29

Stack

LIFO(Last-In-First-Out) - 가장 마지막에 들어온 데이터가 가장 먼저 나감


stack에서 데이터의 삽입, 삭제를 push와 pop으로 부름

stack을 구현하기 위해선, 초기에 pop이 되지 않도록 array가 비어 있는지 확인하는 함수 (isEmpty)가 필요. 타입선언 언어라면 어레이의 사이즈를 정하기 때문에 어레이에 데이터가 가득 찼는지 확인하는 함수 (isFull)이 필요.

Queue

FIFO(First-In-First-Out) - 가장 먼저 들어온 데이터가 가장 먼저 나감


위 그림에서 f(front)는 데이터의 시작위치를 가리키고 r(rear)은 현재 입력된 데이터의 위치를 가리킴


stack과 유사하게 어레이가 비어있는지 확인하는 함수 (isEmpty)와 가득 찼는지 확인하는 함수 (isFull)이 필요함.

Queue의 문제점

데이터를 삭제할 때마다, 포인터가 한 칸씩 앞으로 이동하기 때문에 삭제된 뒷 공간을 활용할 수 없음.

이러한 문제점 때문에 Circular Queue가 등장

Circular Queue

Queue처럼 r을 +1, f를 +1 하는 방식이 아닌 모드(%)를 사용하여 계산

r = (r + 1) % MAX_CIRCULAR_QUEUE_SIZE
f = (f + 1 ) % MAX_CIRCULAR_QUEUE_SIZE


초기 f와 r은 0으로 시작위치가 동일.




Circular Queue에 데이터를 입력하는 함수(add)나 데이터를 삭제하는 함수(delete)를 작성할 때 가장 최상단에 r과 f가 동일한지 비교하는 함수가 무조건 존재해야함.

만일 r과f가 동일하다면 어레이는 더이상 삭제할 데이터가 없거나 이미 가득 찼다는 뜻

'공부 > 자료구조' 카테고리의 다른 글

Binary Search Tree  (0) 2018.08.15
Heap  (0) 2018.08.13
Binary Tree  (0) 2018.08.01
Tree  (0) 2018.07.31
Stack, Queue, Circular Queue  (0) 2018.07.30
ADT, 복잡도(시간복잡도, 공간복잡도), 빅오 분석법  (0) 2018.07.29

추상화(Abstraction) - 중요한 속성만 포함하는 개체.

  • 즉 가장 중요한 것에 초점을 두고 그 이외의 부가적인 것은 무시함.

ADT - Abstract Data Type

한 개의 특별한 데이터 타입의 데이터 표현과 그 타입의 연산을 제공하는 부 프로그램만을 포함하는 클로저이다. 한마디로 사용자에게는 연산에 대한 형식과 제약조건만 알려주고 실제로 어떻게 처리되는지는 표현하지 않는 기능

  • 타입 객체의 표현은 숨겨지고 타입의 정의에서 연산 제공
  • 타입 선언과 연산들은 단일 구문 단위에 포함

자바의 클래스 타입이라 볼 수 있음 

ADT에서 중요한 것은 어떻게 구현되는지는 몰라도 무엇을 하는지 알면 사용자는 만들 수 있다는 점.

복잡도 (Complexity)

프로그램의 실행이 얼마나 오래 걸리는가 (= time complexity)

얼마나 많은 메모리를 사용하는가 (= space complexity)

왜 분석할까?

  • 실제로 실행하기 전에 구현할 알고리즘을 결정
  • 실제 실행시키지 않고  주어진 코드에서 병목현상을 찾을 수 있음

공간복잡도 (Space Complexity)

주어진 알고리즘을 실행시키기 위해 필요한 space는 다음과 같이 두 가지로 분류해 볼 수 있다.

  1. 알고리즘과 무관한 부분: 알고리즘의 특성과는 무관한 부분으로 프로그램 코드를 저장하기 위한 공간, 프로그램을 수행하기 위해 시스템이 필요로 하는 공간 등이 이에 포함된다.
  2. 알고리즘과 밀접한 부분: 알고리즘의 특성과 밀접한 관계가 있는 부분으로서 문제를 해결하기 위해 필요로 하는 공간을 의미한다. 즉, 변수를 저장하기 위한 공간이나 순환 프로그램일 경우, recursion stack 등이 이에 포함된다.

일반적으로 알고리즘의 공간 복잡도를 분석할때는 위의 두가지중 두 번째의 것을 계산하게 된다. 즉, 알고리즘이 문제를 해결하기 위해서 반드시 필요한 부분만을 계산함으로써 주어진 알고리즘의 공간 복잡도를 계산한다.

시간복잡도 (Time Complexity)

시간 복잡도는 알고리즘을 구성하는 명령어들이 몇 번이나 실행이 되는지를 센 결과(frequency count)에 각 명령어의 실행시간(execution time)을 곱한 합계를 의미한다. 그러나 각 명령어의 실행시간은 특정 하드웨어 혹은 프로그래밍 언어에 따라서 그 값이 달라질 수 있기 때문에 알고리즘의 일반적인 시간 복잡도는 명령어의 실제 실행시간을 제외한 명령어의 실행 횟수만을 고려하게 된다.

 이와 같이 알고리즘을 이루는 명령어들의 실행횟수를 계산하여 알고리즘의 시간

복잡도를 구하는 일을 알고리즘의 분석(analysis of algorithm)이라고 한다. 또한, 알고리즘의 분석은 일반적으로 공간 복잡도 보다는 시간 복잡도를 통해서 이루어진다.

 빅 오 분석법 (Big-O Analysis)

빅 오 분석법은 입력 값의 개수에 따라서 알고리즘의 성능을 분석하는 방법. 이 방법을 통해서 간단하게 알고리즘의 성능을 따져볼 수 있음.

Big-O 는 worst case를 기준으로 함. 계산할 때, 차수가 가장 높은 최고차항만 두고 나머지는 버림

O(1): constant

O(n): linear

O(nlogn):

O(n^2): quadratic

O(2^n): expoential


'공부 > 자료구조' 카테고리의 다른 글

Binary Search Tree  (0) 2018.08.15
Heap  (0) 2018.08.13
Binary Tree  (0) 2018.08.01
Tree  (0) 2018.07.31
Stack, Queue, Circular Queue  (0) 2018.07.30
ADT, 복잡도(시간복잡도, 공간복잡도), 빅오 분석법  (0) 2018.07.29

이더리움 계정 (Account)

이더리움 계정에는 20바이트의 주소와 정보를 직접 전달해주는 상태변환을 가지고 있으며 다음 네 개의 필드가 존재합니다.

  • nonce: 각 트랜잭션이 오직 한번만 처리되게 하는 카운터
  • value: 계정의 현재 ether 잔고
  • contract code: 계정의 컨트랙트코드 (값이 없을 수 있음)
  • storage: 계정의 저장공간 (초기설정에는 비어있음)

이더리움의 계정에는 2가지 종류가 있습니다. 외부 소유 계정(External Owned Account - EOA)과 계약 계정(Contract Account - CA)입니다. EOA는 누군가가 소유하고 있는 지갑과 같은 계정이라고 생각하시면 됩니다. CA는 배포된 코드와 저장공간이 추가로 존재하며 스마트 컨트랙트 역할을 할 수 있습니다. 두 가지 계정 중 EOA가 상위 계정이고 새로 생성되는 트랜잭션은 모두 이 EOA에서 시작하게 됩니다. (CA는 EOA가 만든 컨트랙트만 실행할 수 있음 - 생성 X)

EOA는 아무런 코드도 가지고 있지 않으며, 이 계정에서 메시지를 보내기 위해서는 새로운 트랜잭션을 만들고 서명을 해야 합니다. CA는 이러한 메시지를 받을 때마다 자신의 코드를 활성화 시키고 이 활성화된 코드에 따라 메시지를 읽거나 내부 저장공간에 기록하고 다른 메시지들을 보내거나 컨트랙트들을 차례로 생성하게 됩니다. 즉, CA는 컨트랙트를 생성할 수 없고 EOA가 만든 컨트랙트만 실행할 수 있습니다. 모든 컨트랙트에는 해당 컨트랙트가 참이라는 인증이 존재해야 하는데 인증을 담당하는 것은 개인키를 통한 서명이고, 서명을 할 수 있는 것은 EOA이기 때문입니다.

이더리움에서 컨트랙트는 수행되거나 컴파일 되어져야 할 어떤 것이라기 보다는 이더리움의 실행 환경안에 살아있는 자율 에이전트로서 메시지나 트랜잭션이 도착하면 항상 특정한 코드를 실행하고 자신의 이더 잔고와 영속적인 변수들을 추적하기 위해 자신의 키/값 저장소를 직접적으로 통제하는 역할을 합니다. 이러한 개념을 스마트 컨트랙트(Smart Contract)라 부릅니다.


이더리움은 다양한 매개변수를 가지는 타원곡선암호(=ECC)를 사용하여 비대칭 암호 키를 생성합니다. 매개변수는 속도와 보안성을 조절하는 데 사용되며, 이더리움은 secp256k1을 사용합니다. 이더리움의 개인 키와 공개 키는 256bit의 숫자이고, 모든 계정은 주소로 표현됩니다. 공개 키를 이용해 주소를 만드는 순서는 다음과 같습니다.

  1. 공개 키의 keccak-256 해시 생성
  2. 앞 96비트(12바이트)를 버림
  3. 주소를 16진수 문자열로 인코딩. 최종적으로 남은 40개 문자의 바이트 스트링이 유저의 계정 주소.

트랜잭션 (Transaction)

트랜잭션(transaction)은 EOA가 보낼 메시지를 가지고 있는 서명된 데이터 패키지를 말합니다. 이 트랜잭션은 다음 값들을 포함하고 있습니다.

  • to: 메시지 수신처
  • signature: 발신처를 확인할 수 있는 서명
  • value: 발신처가 수신처로 보내는 이더의 양
  • data: 선택적(optional) 데이터 필드 -> 컨트랙트 메시지를 담을 수 있는 데이터 필드
  • gaslimit: STARTGAS 값, 트랜잭션 실행이 수행되도록 허용된 최대 계산 단계수
  • gasprice: GASPRICE 값, 매 계산단계마다 발신처가 지불하는 수수료

트랜잭션은 하나의 서명된 데이터 패키지입니다. 이더를 한 계정에서 다른 계정으로, 또는 컨트랙트로 보내거나 컨트랙트의 함수 호출 및 새 컨트랙트를 배포할 때의 서명으로 쓰입니다. 트랜잭션은 타원곡선암호를 기반으로 하는 디지털 서명 알고리즘인 ECDSA를 이용하여 서명됩니다. 트랜잭션은 메시지 수신자, 송신자를 식별하고 의도를 증명하기 위한 서명, 전송할 이더의 양, 트랜잭션 실행을 위해 허용되는 최대 연산 단계, 트랜잭션 송신자가 각 연산 단계를 위해 지불할 의사가 있는 비용을 포함합니다.


위 트랜잭션이 포함하고 있는 값들 중, 처음 세 항목(to, signature, value)은 암호화폐에서 거의 표준처럼 사용되는 값입니다. 

data는 초기값으로 설정된 기능은 가지고 있지 않지만, 버추얼 머신(EVM)은 컨트랙트가 이 데이터에 접근할 때 사용할 수행코드(opcode)를 가지고 있습니다. 예를 들어, 블록체인 위에 도메인 등록 서비스로 기능하고 있는 컨트랙트가 있을 경우, 이 컨트랙트로 보내지는 data는 두개의 필드를 가지고 있는 것으로 해석할 수 있습니다. 첫번째 필드는 등록하고자 하는 도메인이고, 두번째 필드는 IP 주소입니다. 컨트랙트는 메시지 데이터로부터 이 값들을 읽어서 저장소 내 적당한 위치에 저장합니다. 내용이 복잡할 수 있는데 간단하게 EVM에는 해당 데이터에 어떤 값이 존재하는지 미리 알고 있다고 이해하면 편합니다. 

gaslimit과 gasprice 필드는 이더리움의 anti-DoS 모델에 있어서 매우 중요한 역할을 합니다. 코드 내의 무한루프 (우연이거나 악의적 전부), 또는 계산 낭비를 방지하기 위해 각각의 트랜잭션은 사용할 수 있는 코드 실행의 계산 단계 수를 제한하도록 설정되어야 합니다. 계산의 기본 단위는 gas이고 보통, 계산 단계는 1 gas의 비용이 소요되지만 어떤 연산은 더 비싼 계산 비용을 치루거나 상태의 일부분으로 저장되어야 하는 데이터의 양이 많을 경우엔, 더 많은 gas 비용이 필요하게 됩니다. 또한 트랜잭션 데이터에 있는 모든 바이트는 바이트당 5 gas 의 수수료가 듭니다. 이러한 수수료 시스템의 의도는 만약 해커가 이더리움이나 dAapp을 해킹했을 때, 해커들이 실행하는 모든 리소스에 비례하여 강제로 수수료를 지불하게 하는데 있습니다.

메시지 (Message)

위 트랜잭션에서 설명한 것과 같이 컨트랙트는 다른컨트랙트에게 메시지를 전달할 수 있습니다. 메시지는 따로 저장될 필요가 없는 이더리움의 실행 환경(EVM)에서만 존재하는 가상의 객체입니다. 메시지는 다음 값들을 포함하고 있습니다.

  • from: (암묵적으로) 메시지 발신처
  • to: 메시지 수신처
  • value: 메시지와 함께 전달되는 이더
  • data: 선택적 데이터 필드
  • gaslimit: STARTGAS 값

메시지는 EOA가 아닌 컨트랙트에 의해 생성된다는 것을 제외하면 트랜잭션과 유사합니다. 현재 코드 수행을 하고 있는 컨트랙트가 메시지를 생성하고 실행하라는 수행코드(opcode)를 만나게 되면 메시지를 생성합니다. 트랜잭션과 마찬가지로, 메시지는 해당 코드를 실행하는 수신자 계정(컨트랙트 계정)에 도달하게 됩니다. 따라서, 컨트랙트는 EOA가 하는 것과 정확히 같은 방식으로 다른 컨트랙트와 관계를 맺을 수 있습니다. 트랜잭션이나 컨트랙트에 의해 할당된 gas 허용치는 그 트랜잭션과 모든 하위 실행에 의해 소모된 총 gas 에 적용됩니다. 예를 들어, EOA인 A가 B에게 1000 gas와 함께 트랜잭션을 보내고, B는 600 gas를 소모한 뒤 C에게 메시지를 보내고, C의 내부 실행에 300 gas를 소모한 후 반환하면, B는 gas가 모두 소모되기 전에 100 gas를 더 사용할 수 있습니다.

예시

A가 B에게 5ETH를 전송하면서 이더리움이 100만원이 되면 B가 2ETH를 C에게 전송 

위와 같은 트랜잭션을 만든다고 가정합니다. 


우선 A는 자신의 EOA로 이 내용을 담은 트랜잭션을 만들어서 서명을 하고 블록에 포함시켜야 합니다. A가 보낸 트랜잭션은 모든 노드들이 검증한 후 블록에 담겨 B에게 전송됩니다. 이 트랜잭션에는 이더를 송금하는 것 외에 이더리움이 100만원이 되면 C에게 2ETH 전송 이라는 조건을 담은 메시지가 들어있어 B의 CA는 이 메시지를 저장됩니다. 이더리움이 100만원이 되면, B의 CA는 A로부터 받은 계약을 자동으로 실행시킵니다. 3ETH를 B의 EOA로 전송하고 남은 2ETH를 C의 EOA로 전송합니다. C에게 전송할 땐 조건이 없어 CA로 보낼 필요가 없습니다.

이렇게 자동으로 실행되는 것이 스마트 컨트랙트입니다.

+ Recent posts