#blockchain

Signing and verifying in ethereum

이더리움에서 eth 를 송금하거나 스마트 컨트랙을 부르는 등의 transaction 을 일으키기 위해서는 signing 이 필요하며, 블록체인 상에서 사용자를 인증하거나 메세지의 유효성을 검증하기 위해 signing 과 validation 이 사용된다.

가령, Alice 가 Bob 에게 어떤 메세지를 보내는 상황을 전제해 보자. 여기서 Bob 이 메세지를 받았다면, 인터넷 네트워크에서는 누구든지 메세지를 보낼 수 있고, 나쁜 의도를 가진 다수의 사용자들이 존재하기 때문에, 진짜 그 메세지가 Alice 로 부터 온 것인지 또, 메세지의 내용이 Alice 가 보낸 그 내용이 맞는지에 대해 의문을 품을 것이다. 이 때문에 블록체인 에서는 signing 의 개념이 존재하며 여기서 그 유효성을 검증하고자 하는 대상을 message 라고 한다.

그렇다면 이제 어떻게 signgingvalidation 이 진행되는 지를 알아보자.

먼저 위 사례에서 Alice 는 자신의 Private Key 로 해당 메세지에 서명을 한다. 이더리움에서 제공하는 web3 를 통해 다음과 같은 간략한 명령을 통해 이런 signing 이 진행되게 된다.

1
web3.eth.accounts.sign(message, privateKey);

위 에서 message 는 유효성을 검증하기 위한 메세지로 String 타입이다.

위 과정을 거치면 사용자가 서명을 한 메세지를 의미하는 Signature Object 가 나오게 되는데 그 형식은 다음과 같다.

1
2
3
4
5
6
7
8
9
{
message: 'Some data',
messageHash: '0x1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655',
v: '0x1c',
r: '0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd',
s: '0x6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a029',
signature: '0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f\
5fd6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a0291c'
}

위에서 알 수 있듯이 Signature 에는 사용자의 원래 메세지 뿐만 아니라 messageHash 라는 "\x19Ethereum Signed Message:\n" + message.length + message 의 양식으로 포맷팅된 후 keccak256(SHA3) 으로 해쉬된 해시값을 비롯하여 signature 를 구성하는 v, r, s 와 실제 서명인 Signature 가 포함된다. 여기서 r 과 s 는 각각 Signature의 첫 32byte 와 뒤 32byte 를 나타낸다.

* 위의 MessageHash 는 web3 가 제공하는 hashMessage(message) 함수 호출을 통해서도 얻을 수 있다.

위처럼 sign 을 완료했다면, 해당 Signature 를 받은 사용자는 다음과 같은 recover 함수 호출을 통해 올바른 사용자인지를 판별 할 수 있다.

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
web3.eth.accounts.recover(signatureObject);
web3.eth.accounts.recover(message, signature [, preFixed]);
web3.eth.accounts.recover(message, v, r, s [, preFixed]);

web3.eth.accounts.recover({
messageHash: '0x1da44b586eb0729ff70a73c326926f6ed5a25f5b056e7f47fbc6e58d86871655',
v: '0x1c',
r: '0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd',
s: '0x6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a029'
})
> "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23"

// message, signature
web3.eth.accounts.recover('Some data', '0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a0291c');
> "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23"

// message, v, r, s
web3.eth.accounts.recover('Some data', '0x1c', '0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd', '0x6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a029');
> "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23"

EIP712

What is EIP712

EIP 712 란 Ethereum Improvement Proposals 712 의 약어로 이더리움에서 향후 지원하게 될 다양한 제안들중 하나이다. 과거 사용자가 어떤 거래를 함에 있어 sign 을 할때에는 sign 의 대상이 되는 message 가 hash 화 되어 존재하기 때문에, 서명을 하는 사용자가 자신이 서명하는 내용에 대해 잘 알기 힘든 문제가 있었으며, 가령 유사한 해시값을 가진 피싱 사이트로 유도하여 사이닝을 유도한다던가 하는 다양한 위험에 노출되어 있었다.

이를 해결하기 위해 안전하고 값이 변조되지 않는 해싱을 보장하면서도 readability 를 가질 수 있는 서명방법을 고안하게 되었으며 그 제안내용이 EIP712 에 제안되었다.

EIP712 를 통해 사용자는 자신이 서명하는 정보에 대해 명확하게 인지할 수 있게 된다고 볼 수 있다.

가령, 위에서처럼 일반적인 signing의 과정에서는 sign 을 요청하는 사람이 제공하는 message값(주로 hash값) 만을 보고 사용자가 sign 을 진행하지만 EIP712 에서는 json 데이터를 보고 자신이 서명하는 데이터를 명확히 알 수 있다.

다음은 EIP712 를 통해 수행되는 서명의 방법을 나타낸다.

먼저 서명을 하고자 하는 데이터의 형태를 정의하는데 이러한 typed structured data 를 먼저 정의하는 것으로 서명이 시작된다. 아래와 같이 서명을 하고자 하는 메세지를 json 형태로 정의를 한다. 서명자는 아래와 같은 데이터를 통해 어떤 내용에 자신이 서명을 하는지 알 수 있다.(아래의 메세지는 meta mask 등의 지갑 어플리케이션에서 파싱되어 보여지며, EIP712 는 이러한 지갑 어플리케이션에서 제공하는 기능을 말미암에 제공된다.)

컨트랙트 도메인 타입의 정의

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const domain = [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" },
{ name: "salt", type: "bytes32" },
];

const bid = [
{ name: "amount", type: "uint256" },
{ name: "bidder", type: "Identity" },
];

const identity = [
{ name: "userId", type: "uint256" },
{ name: "wallet", type: "address" },
];
1
2
3
4
5
6
7
var message = {
amount: 100,
bidder: {
userId: 323,
wallet: "0x3333333333333333333333333333333333333333"
}
};

위처럼 서명하고자 하는 message 를 정의하였다면, 해당 메세지가 어떤 도메인 사업자(즉 DAPP 사업자로 이해할 수 있다) 에서부터 온 메세지인지를 나타내는 구분자인 Domain Separator 를 정의해 준다.

1
2
3
4
5
6
7
const domainData = {
name: "My amazing dApp",
version: "2",
chainId: parseInt(web3.version.network, 10),
verifyingContract: "0x1C56346CD2A2Bf3202F771f50d3D14a367B48070",
salt: "0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558"
};

name: DAPP 혹은 Protocol 의 이름

version: DAPP 혹은 Platform version

chainId: 테스트 넷인지 메인넷인지 등을 구분하는 chain id 로 EIP155 에서 제안되었다.

verifyingContract: 해당 signature 를 verify 할 스마트 컨트랙트의 주소

salt: 32 바이트의 hard code 된 유니크한 값으로 컨트랙트와 DAPP 사이에 공유되어 다른 DAPP 과 구분되는 최후의 보루이다.

message type 과 Domain separator 가 정의되었다면 다음과 같이 Json 형태의 data 를 만들고 이를 stringily 시켜 sign 을 요청한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const data = JSON.stringify({
types: {
EIP712Domain: domain,
Bid: bid,
Identity: identity,
},
domain: domainData,
primaryType: "Bid",
message: message
});

web3.currentProvider.sendAsync(
{
method: "eth_signTypedData_v3",
params: [signer, data],
from: signer
},
function(err, result) {
if (err) {
return console.error(err);
}
const signature = result.result.substring(2);
const r = "0x" + signature.substring(0, 64);
const s = "0x" + signature.substring(64, 128);
const v = parseInt(signature.substring(128, 130), 16);
// The signature is now comprised of r, s, and v.
}
);

data 내의 types 필드는 스마트 컨트랙트 내에서의 데이터 구조를 나타내며 반드시 struct name 과 정확히 일치해야한다. 또한 PrimaryType 은 데이터 구조에서의 최상위 자료 구조형이 무엇인지 명시한다.

Validation in Smart contract

클라이언트에서 signing 을 위해 formatting 과 hashing 을 거친 것처럼 같은 내용의 코드가 Smart Contract 에도 포함되어야 한다. 이 과정을 통해 ecrecover 함수를 통해 해당 서명에 사인한 account 의 address 를 알 수 있다.

인증을 위한 Contract 를 위해 제일 먼저 EIP712 에서 앞서 정의한 data type 을 struct 로 정의해야 한다.

1
2
3
4
5
6
7
8
9
struct Identity {
uint256 userId;
address wallet;
}

struct Bid {
uint256 amount;
Identity bidder;
}

그 다음으로는 위 data structure 에 맞는 type hash 를 정의해야 하며 그 코드는 다음과 같다.

1
2
string private constant IDENTITY_TYPE = "Identity(uint256 userId,address wallet)";
string private constant BID_TYPE = "Bid(uint256 amount,Identity bidder)Identity(uint256 userId,address wallet)";

여기서 comma 와 bracket 사이에 공백이 들어가지 않는것을 유념하자. 또한, parameter 의 이름과 자료형이 클라이언트의 자료형과 변수명과 완벽하게 일치해야 한다.

또한 다음과 같이 Domain Separator 도 다음과 같이 hashify 되어야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
uint256 constant chainId = 1;
address constant verifyingContract = 0x1C56346CD2A2Bf3202F771f50d3D14a367B48070;
bytes32 constant salt = 0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558;
string private constant EIP712_DOMAIN = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)";
bytes32 private constant DOMAIN_SEPARATOR = keccak256(abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256("My amazing dApp"),
keccak256("2"),
chainId,
verifyingContract,
salt
));

아래와 같이 각 data 를 hashify 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function hashIdentity(Identity identity) private pure returns (bytes32) {
return keccak256(abi.encode(
IDENTITY_TYPEHASH,
identity.userId,
identity.wallet
));
}

function hashBid(Bid memory bid) private pure returns (bytes32){
return keccak256(abi.encodePacked(
"\\x19\\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(
BID_TYPEHASH,
bid.amount,
hashIdentity(bid.bidder)
))
));
}

마지막으로 다음과 같이 signature 를 verify 하는 함수를 작성해 준다.

1
2
3
function verify(address signer, Bid memory bid, sigR, sigS, sigV) public pure returns (bool) {
return signer == ecrecover(hashBid(bid), sigV, sigR, sigS);
}

Keccak256 hashing

이더리움에서는 SHA3 해싱을 위해 keccak256 을 사용한다.

What is DEX?

DEXDecentralized Exchange 의 약어로 중간자 없이 가상화폐 지갑과 지갑 사이의 p2p 교환을 해주는 것이다.

DEX 에서는 custody 즉, 누가 거래에서의 키를 보관하는가에 대한 중대한 이슈가 있으며, DEX 는 모든 교환과정에 있어 개인이 키를 소유하고 완변하게 decentralized 되 토큰의 교환을 하는 것에 그 목적이 있다.

Basic Procedure

본 프로젝트에서 DEX 의 기본적인 프로세스는 다음과 같다.

먼저, 브라우저 상에서 토큰의 교환을 원하는 사용자가 매도 혹은 매수 주문을 걸면, 해당 주문정보를 EIP 712 로 서명한 서명정보와 함께 전달하면, Relayer API 를 통해 해당 기록이 off-chain 상의 orderbook 에 기록되게 된다. 그 이후, orderbook 을 조회하여 여러 주문들의 쌍을 받아와 교환이 가능한 거래쌍을 선정하여 스마트 컨트랙으로 전송한다.(즉, 하나의 taker order와 하나 이상의 maker order 들을 전달하며, 모든 주문은 서명이 완료된 주문이다. 여기서, 전송을 하는 과정에 있어 주문에 필요한 다양한 정보들을 전부 parameter 로 전달하면 gas 비 문제등 많은 문제들이 존재하기 때문에, 거래에 필요한 데이터를 data 라는 필드로 만들어 OrderParam 에 포함하여 전달한다.

또한, 위 과정을 진행함에 앞서 실제 거래의 주체가 아닌 relayer 를 통해 자금을 교환하기 때문에 플랫폼에서 만들어둔 relayer account 를 approve 하여 일정 자금에 대한 사용권한을 주어야 한다.

스마트 컨트랙에 전달된 인자들이 들어오면, 컨트랙은 주어진 주문 쌍을 분석하여 거래를 진행하기 위한 Result 들의 집합으로 나누고, 해당 주문을 filled 라는 orderHash:amount 쌍에 기록한다.

dex process

Smart Contract

주문의 전달

모든 주문은 Order Server 내의 orderbook 에 기록되고, 매칭이 가능한 조합들을 모아 스마트 컨트랙트의 matchOrders 를 호출하며, 그 인자는 다음과 같다.

1
2
3
OrderParam memory takerOrderParam,
OrderParam[] memory makerOrderParams,
OrderAddressSet memory orderAddressSet

여기서 order param 은 주문에 필요한 maker와 taker 의 요청정보이며, 그 형태는 다음과 같다.

OrderParam

1
2
3
4
5
6
7
8
struct OrderParam {
address trader;
uint256 baseTokenAmount;
uint256 quoteTokenAmount;
uint256 gasTokenAmount;
bytes32 data; # 주문정보를 조합하여 32byte 로 축약, 가스비 절약 목적
OrderSignature signature; # EIP 712 서명
}

위에서 base tokenquote token 이 무엇인지 헷갈릴 수 있는데, taker가 매도 혹은 매수를 할때 기준이 되는 토큰을 base token이라고 한다. 즉, taker 가 특 정 토큰을 구매한다고 하면 그 구매의 대상이 되는 토큰을 base token 이라고 하며, 판매를 한다고 하면, 판매의 대상이 되는 그 토큰을 quote token 이라고 한다.

또한 여기서 OrderSignature 는 브라우저가 생성하고자 하는 주문정보를 EIP 712 로 서명한 서명정보로 추후 스마트 컨트랙트에서 해당 사용자의 주문정보를 해시하여 위 시그내처를 통해 유효성을 검증하는 과정을 거친다.


인증과정에서의 데이터의 흐름

사용자의 orderParam 쌍 => param 의 data property 에서 order rebuild => EIP712 hash 를 orderParam 의 signature 로 validate


* 여기서 signature 의 목적은 무엇일까?

여기서 signature 는 사용자가 본래 요청하고자 했던 주문정보가 스마트 컨트랙트에서 체결되는 시점에도 해당 사용자가 요청한 주문과 내용이 맞는지 검증하는 것이다.

가령, DEX 에서 두 사용자가 거래를 진행할때 다른 사용자가 특정 사용자의 계정을 스마트컨트랙에 거래를 요청하는 경우, 주문정보가 동일하더라도 주문을 작성한 유저가 요청한 주문이 아니므로 거래가 이루어 져서는 안되며, 특정 주문내용을 바꾸어서 컨트랙트에 체결을 요청하는 등 다양한 악용을 막는 역할을 수행한다.

* EIP 712 란 무엇인가?

EIP 712 란 Ethereum Improvement Proposals 712 의 약어로 이더리움에서 향후 지원하게 될 다양한 제안들중 하나이다. 과거 사용자가 어떤 거래를 함에 있어 sign 을 할때에는 sign 의 대상이 되는 message 가 hash 화 되어 존재하기 때문에, 서명을 하는 사용자가 자신이 서명하는 내용에 대해 잘 알기 힘든 문제가 있었으며, 가령 유사한 해시값을 가진 피싱 사이트로 유도하여 사이닝을 유도한다던가 하는 다양한 위험에 노출되어 있었다.

이를 해결하기 위해 안전하고 값이 변조되지 않는 해싱을 보장하면서도 readability 를 가질 수 있는 서명방법을 고안하게 되었으며 그 제안내용이 EIP712 에 제안되었다.

EIP712 를 통해 사용자는 자신이 서명하는 정보에 대해 명확하게 인지할 수 있게 된다고 볼 수 있다.

EIP 서명의 절차에 대해 간략하게 소개하면, 먼저 서명을 하고자 하는 데이터의 형태를 정의하는데 이러한 typed structured data 를 먼저 정의하는 것으로 서명이 시작된다. 데이터의 정의가 완료되면, 여러 DAPP 들 사이에 구별되기 위한 domain separator 를 정하여 서명을 검증할 스마트 컨트랙트의 주소부터 version, salt 등의 데이터로 구성된다.

EIP 서명이 완료되면, 사용자는 signature 를 얻게 되며 추후 스마트 컨트랙트는 주문정보를 직접 해싱하여 사용자가 제공한 signature 로 validation 을 진행하여 유효성을 검증한다.

거래의 체결

matchOrders 함수가 호출되는 시점에 매칭된 오더들의 정보가 filledorderHash:filledAmount 의 mapping 형태로 기록되며, 만약 주문이 체결되었다면 기존에 있던 주문들에 새로운 주문이 발생하면서 체결이 될 것이다.

여기서 기존에 있던 주문을 한 사용자를 maker 라 칭하며, 주문을 체결하는 주문을 발생시킨 사용자를 taker 라 명명한다.

또한, 거래의 특성상 taker 가 넣은 주문을 만족시키는데 필요한 하나 이상의 주문이 필요하게 되므로 주문이 매칭 될 때에는 하나의 taker 주문에 한개 이상의 maker 주문이 매칭된다.

Taker 의 매도 주문

taker 의 매도주문으로 인해 주문이 체결되는 경우의 시나리오는 다음과 같으며, n개의 거래쌍이 이루어 졌다고 전제한다.

  1. maker 가 relayer 에게 만족하는 quote token 과 maker fee, maker gas fee(maker rebate fee 는 차감한다.) 를 n번 지급한다.
  2. takermaker 에게 만족하는 base token 을 n번 지급한다.
  3. relayertaker 에게 만족하는 quote token 중 taker gas fee 를 제하고 1회 지급한다.

dex_taker_sell

Taker 의 매수 주문

dex_taker_buy

Getting started with ethereum

Kinds of accounts

이더리움에는 두가지 종류의 account 가 있는데, External AccountContract Account 가 그것이다.

먼저 External Account 는 공개키 방식의 계정이며, address 역할을 하는 public keynonce 로 구성이 되며, Contract Account 는 일반적인 smart contract 이다.

여기서 account 와 account 사이에 자금이 이동하면 그것을 transaction 이라고 말한다.

Transaction

이더리움에서 transaction 이란 하나의 EOA 로부터 다른 account 로 전송되는 message 를 포함한 signed data packet 을 의미하며 다음과 같은 정보들을 담고 있으며, EOA 로 부터 EOA 로 가는 경우는 이더를 송금하는 것을 내포하고, 만약 수신자가 Contract Account 라면 해당 contract 가 어떤 코드를 실행하도록 trigger 하는 것이 된다.

  • receipient
  • signature
  • value
  • data: which can contain the message sent to a contract

여기서 data 는 contract 가 실행에 필요한 정보를 들고 있으며 Contract ABI(Application Binary Interface) 에 따라 컨트랙트와 소통한다. 이 ABI 는 외부 와컨트랙트 간의 상호작용에 필요할 뿐만 아니라 contract 간의 상호작용에도 적용된다.

따라서 data 는 다음의 규약에 따라 인코딩 되어 사용되며 ABI(Application Binary Interface 에 따라 정의된다.

함수 선택자

data 의 함수 시그니처의 Keccak-256 (SHA-3) hash 의 첫 4바이트는 어떤 함수를 호출할지를 나타내며 function 시그니처로 부터 도출된다.

1
2
3
4
5
6
7
pragma solidity >=0.4.16 <0.6.0;

contract Foo {
function bar(bytes3[2] memory) public pure {}
function baz(uint32 x, bool y) public pure returns (bool r) { r = x > 32 || y; }
function sam(bytes memory, bool, uint[] memory) public pure {}
}

위의 예제에서 baz 함수를 호출하고자 하는 transaction 의 data의 함수선택자는 0xcdcd77c0 인데 이는 method 의 id 로 ASCII format 으로 작성된 function signature 인 baz(uint32,bool 의 Keccak hash(sha3) 의 첫번째 4 바이트이다.

함수 Parameter

또한 해당 함수의 parameter 로 69와 true 를 제공한다면 69를 32바이트 로 패딩한 0x0000000000000000000000000000000000000000000000000000000000000045 가 값이 된다. 0x0000000000000000000000000000000000000000000000000000000000000001

ABI(Application Binary Interface)

컴퓨터 과학에서 흔히 말하는 ABI 는 두가지 종류의 binary 프로그램 모듈 사이의 인터페이스이다. 쉬운 예로는 libraryoperating 시스템의 경우가 있는데, 하나의 라이브러리는 여러 시스템 상에서 동작해야 하므로 해당 소스코드가 다양한 운영체제에서 동작하기 위해서는 약속된 인터페이스가 필요하다. 또 한 예로는 유저에 의해 실행되는 프로그램의 예가 있는데 가령 여러 운영체제에서 해당 프로그램을 실행하여도 동작하기 위해서는 이러한 ABI 가 정의되어 있어야 한다.

이와 같은 맥락에서 이더리움 에서의 ABI 란 특정 함수가 이더리움에서 실행되기 위한 포맷팅의 규약으로써 이해될 수 있다.

아래는 스마트 컨트랙트 내에서 특정 데이터를 ABI 인코딩 하는 것을 보여준다.

1
abi.encode("AAAA")

위 코드는 아래와 같이 3단어로 구성된 96(32byte *3) 사이즈의 바이트 문자열을 리턴한다.

1
2
3
0x0000000000000000000000000000000000000000000000000000000000000020
0x0000000000000000000000000000000000000000000000000000000000000004
0x4141414100000000000000000000000000000000000000000000000000000000

한 줄씩 살펴보면 먼저 첫번째 라인은 해당 문자열의 starting offset(32 in decimal) 를 32byte 문자열에 padding 한 것이며, 두번째 문자열은 인코딩 하는 데이터의 길이인 4를 32바이트 문자열에 padding 하여 나타낸다. 마지막으로 세번째 문자열은 실제 우리의 데이터인 “AAAA” 를 UTF-8 인코딩하여 32 바이트 문자열에 padding 하여 나타내어 준다.

위의 encoding 방식보다 다소 간편하게 인코딩을 하고 싶다면 abi.encodePacked("AAAA") 라는 함수를 사용할 수 있다. 이 함수는 32바이트보다 작은 문자는 그냥 해당 문자열을 바이트로 출력하고 32바이트에 padding 하지도 않는다.

한가지 흥미로운 사실이 있는데, keccak256 을 사용하여 hashing 을 할때 복수개의 인자를 전달하면 이것을 내부적으로 abi.encodePacked 함수로 인코딩 하여 해싱을 한다는 것이다. 현재는 복수개의 인자를 전달하면 warning 을 출력하기는 하지만, 알아두도록 하자.

다음은 Keccak256 에서 abi.encodePacked 를 사용하는 예이다. 아래의 두 hashing 은 정확히 동일한 역할을 수행한다.

1
keccak256("AAAA", "BBBB", 42);
1
keccak256(abi.encodePacked("AAAA", "BBBB", 42));

사토시 나카모토의 Bitcoin 논문

이번 포스트에서는 현대의 블록체인 기술의 근간이 된 사토시 나카모토의 bitcoin 논문을 설명하고, 블록체인의 핵심 개념에 대해 적어보고자 합니다.

우리가 흔하게 오프라인상에서의 금전을 거래할때와는 다르게 인터넷상에서의 거래에는 기술적으로 해결할 수 없는 문제가 존재하는데 그것은 바로 특정 거래가 두번 일어나게 되어 존재하지 않던 재화가 전산상에 생겨나게 되는 것입니다. 이것이 어떻게 가능하냐고 할 수 있지만, 인터넷에서의 거래란 사실 데이터베이스라는 정보의 창고에 새로운 기록을 작성하고 있던 수치를 줄이거나 올리는 단순한 작업이기 때문에 전산상의 오류나 혹은 해커의 공격에 의해 내가 하지 않은 거래가 두번 기록이 될 수 있게됩니다. 이러한 문제를 double spending problem 이라고 하며, 궁극적으로 사토시는 이 double spending problem 을 해결하기 위한 연구를 시작합니다.

사토시는 이를 해결하기 위해 매 시간의 timestamp를 기반으로 하는 p2p네트워크를 기반으로 모든 거래 정보는 블록화 되어 체인 구조로 연결되고 동기화되는 일종의 온라인 체인 시스템을 고안하게 됩니다. 즉, 온라인 상에서 일어나는 모든 거래에 그 시간을 ms 단위의 정밀도로 기록을 한 뒤에 온라인 상에서 모든 사람들이 합의를 하여 각 거래의 신뢰성을 판단하고 그 거래기록을 한데 모아 블록으로 만들어 이어붙인다면 모두가 인정할 수 있는 분산 원장을 만들 수 있지 않을까 라는 생각을 하게 된 것입니다.

이렇게 체인을 연결해 가는 과정에는 많은 컴퓨팅 파워가 필요하게 되었고, 가장 많은 CPU 파워를 가진 컴퓨터 집단이 가장 긴 체인을 생성할 수 있을 것이며 이를 신회하는 네트워크 구조가 바로 블록체인 네트워크 입니다.

즉, 사토시 나카모토가 제안한 bitcoin의 궁극적이고 본질적인 목표는 제 3 기관의 개입 없이 화폐를 주고 받는 것이었습니다.

블록체인 내에서의 거래 기록

비트코인에에서 거래는 UTXO(Unspent Transaction Output) state model 에 따라 기록됩니다. 이는 이름 그대로 하나의 거래 내역에서 사용되지 않은 양을 통해서 자금의 상태를 기록함을 의미합니다.

즉, 비트코인에서 Transaction 이란 사용되고 남은 Bitcoint 의 양을 가지는 일종의 화폐 자체로 이해할 수 있습니다. 가령 5BTC 짜리 Transaction, 1BTC 짜리 트랜잭션처럼 각 Transaction 은 누군가에게 소유된 화폐로 이해할 수 있고, 그 화폐가 이미 소진되었다면 해당 화폐를 소진한 주체가 output 에 기록되고 아직 소진되지 않았다면 그 화폐를 소진할 수 있는 사용자의 주소가 명시되어 있다고 보면 됩니다.

다음은 실제 비트코인에서 Transaction Model 의 일부입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
class CTransaction
{
public:
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;

...

private:
const uint256 hash;

...
}

위에서 알 수 있듯이 비트코인에서 하나의 Transaction 에는 Vin 과 Vout 이라는 값이 존재하며, 각 model 의 구조는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14

class CTxIn
{
public:
COutPoint prevout;
CScript scriptSig;
}

class CTxOut
{
public:
CAmount nValue;
CScript scriptPubKey;
}

각 속성을 하나씩 살펴보면, 거래를 이루는 것은 CTxIn 과 CTxOut 두가지로 구성되고, CTxIn 에는 해당 Transaction 이 어떤 Transaction 의 몇번째 output 을 기준으로 거래가 시작되는지를 나타내며 COutPoint 는 실제로 특정 Transaction 의 hash 값과 output 의 index 값을 통해 생성된 값입니다. ScriptSig 는 해당 화폐를 사용한 사용자의 서명으로 어떤 사용자가 해당 화폐를 사용하였는지를 나타내며, 이는 이전 Transaction CTxOut 의 scriptPubKey 의 소유자가 서명한 서명입니다.

CTxOut 의 nValue 속성은 실제 BTC 의 양이 명시되며 1억 분의 1 BTC 인 Satoshi 를 기준화폐로 사용합니다. scriptPubKey 는 해당 화폐를 사용할 수 있는 사용자의 address 이며, 해당 사용자가 이 Transaction 에 서명하여 다음 Transaction 에 기록함으로써 화폐를 사용할 수 있습니다.

여기서 중요한 사실을 알 수 있는데, 그것은 바로 블록체인 내에서 거래(transaction) 는 이전 거래의 정보(이전 transaction’has value) 를 포함하기 때문에 모든 거래는 시간 순으로 동기화 될 수 있다는 것입니다.

이렇게 모든 거래의 내역들을 한데 모아 블록으로 저장하며, 특정 시간을 주기로 그 시간동안 일어난 모든 거래를 한데 모아 새롭게 블록을 생성하는 작업을 거치는데, 이는 각 거래를 일종의 트리 형태로 나열하고 이를 해쉬라고 불리는 암호화 과정을 거쳐 해시를 만들어 내는 것입니다. 그리고 새로운 블록을 생성함이란 이렇게 복잡하게 암호화된 해쉬값을 먼저 풀어낸 컴퓨터가 그 보상을 가지는 방식으로 기여를 하게 됩니다.

여기서 컴퓨터가 해쉬값을 풀어내는 것은 아주 단순하게 생각하면 무수히 많은 숫자와 문자열(nonce)을 계속해서 대입하면서 맞는 값이 나올때까지 대입해 보는 것이라 볼 수 있습니다.각 블록의 해쉬값을 먼저 풀어낸 노드가 새롭게 블록을 생성합니다.

이를 위해서는 엄청난 컴퓨팅 파워가 필요하며, 이를 통해 상대적으로 더 많은 컴퓨팅 파워를 가지는 믿을 수 있는 노드들의 컴퓨팅 파워를 통해 올바른 블록을 생성하게 됩니다.

네트워크의 동작

블록체인 네트워크는 다음과 같은 순서에 따라 이루어 집니다.

  1. 모든 transactions 는 모든 노드에 전파된다.
  2. 모든 노드는 각 트랜잭션을 모아서 블럭을 구성한다.
  3. 각 노드는 만든 블럭의 해시를 풀어낼 nonce 값을 찾기 위해 연산을 시작한다.
  4. 어떤 노드가 nonce를 찾아냈다면 다른 모든 노드에게 자신이 가진 블록을 전파한다.
  5. 블록을 받은 노드들은 받은 블록 안의 모든 트랜잭션들이 유효하고 이미 지불된 것이 아닐 때에만 블록을 받는다.
  6. 블록을 받은 노드들은 받은 블록의 해쉬값을 previous hash로 하는 새로운 블록은 만드는 것에 착수함으로써 다른 노드들에게 해당 블록을 승인하였음을 알린다.
  7. 만약 노드가 동시에 두개의 블록을 받는다면 처음 받은 블록을 기준으로 작업을 시작하지만 이후로 받은 블록들도 저장해 둔다. 이렇게 여러 블록들은 개별적인 브랜치를 형성하고 특정 브랜치가 길어지면 가장 긴 브랜치의 블록들을 승인하여 체인을 이어간다.

만약 노드가 다음 블록을 받지 못했다 하더라도 문제가 되지 않는데, 이는 그 다음 블록을 받게 되면 노드 자체가 자신이 받지 못한 블록을 인지하고 다른 노드들에게 이를 요청하기 때문이다. 또한 모든 트랜잭션들을 매우 많아서 빠트리면 트랜잭션이 있더라도 블록들은 계속 생성되기 때문에 빠트린 transaction들은 무시되고 넘어간다.

보상의 원리

블록체인 시스템의 참여자들을 컴퓨팅 파워를 통해 그 신뢰가 유지되는 시스템이므로, 모든 참여자들이 계속해서 컴퓨팅 파워를 제공하도록 동기 부여 하기 위해 인센티브를 부여하며, 이는 바로 블록을 생성한 노드에게 최초의 트랜잭션을 발행하도록 하는 것으로 이것이 우리가 일반적으로 알고있는 코인의 채굴하는 과정이 됩니다.

화폐가치의 분할

위 내용에서와 같이 우리는 모든 코인은 그 전의 소유자들의 정보를 가진다고 알아보았으며, 이는 현실 세계에서 특정 1달러 지폐에 이제까지의 소유자들이 적혀있는 것에 비유될 수 있다고 하였습니다. 하지만 좀 더 작은 단위 혹은 더 큰 단위의 돈을 송금하는 경우를 생각해 보면, 1달러 지폐 하나를 다른 누군가 혹은 수십명의 다른 사람들과 공유하는 것을 생각할 수 있습니다.

이것은 하나의 transaction이 여러 개의 input 및 output value를 가짐으로써 해결 될 수 있는데, 하나의 transaction은 다른 여러 사람들에게 지불될 수 있으며 모든 내용이 하나의 transaction에 작성되어 있도록 하는 것입니다. 쉽게 말하면 1달러 지폐를 현재 가지고 있는 사람이 복수 명이 되어도 괜찮다는 것으로 생각될 수 있습니다.

이번 포스트에서는 사토시 나카모토의 논물을 쉽게 요약하여 블록체인의 핵심 원리에 대해 알아보았습니다.

가상화폐 시장의 열기가 죽어가는 현 시점이지만, 블록체인의 효용과 사토시 나카모토가 만들고자 했던 새로운 화폐경제 시스템의 가치는 보존되었으면 하는 바람으로 글을 마칩니다.

LNH

두나무의 블록체인 개발 플랫폼, 루니버스

이번 포스트에서는 두나무의 블록체인 개발 플랫폼 루니버스에 대해 알아보고자 합니다.

루니버스란?

블록체인 기술에 대한 관심은 계속해서 증가하고 있지만, 블록체인의 특성상 메인넷을 구성하고 자체 코인을 발행하는 것은 상당한 기술력을 필요로 하고, 네트워크를 구축했다 하더라도 다른 블록체인 네트워크와 접점을 만들고 블록체인 플랫폼의 참여자를 만들어 나가는 것 또한 매우 어려운 일이기에, 국내에서 성공적으로 운영되고 있는 블록체인 서비스는 사실상 전무하다고 볼 수 있습니다.

두나무의 루니버스란 이처럼 개발의 진입장벽이 높은 블록체인 기술의 장벽을 낮추고 개발자라면 누구나 쉽게 Decentralized Application을 만들 수 있도록 하겠다는 목표로 블록체인 서비스 개발 플랫폼인 ‘루니버스’ 의 출시를 준비하고 있습니다.

루니버스는 마치 아마존의 클라우드 서버처럼 클릭 몇번으로 네트워크 상에 자체적인 블록체인 네트워크를 구축하도록 도와주며, 해당 블록체인 네트워크에 토큰을 발행하고 Dapp 을 올리는 등의 일련의 작업을 매우 쉽게 만들어주어 개발자들에게 인종의 블록체인 네트워크에 대한 쉽고 간편한 인터페이스를 제공해 줍니다.

루니버스 플랫폼을 통해서 개발자는 간편한 REST API를 통해 블록체인 상의 대부분의 기능을 수행할 수 있게 되기에 오직 비즈니스 로직에만 집중하여 블록체인 서비스를 만들 수 있는 환경을 제공받습니다. 즉, 루니버스를 이용하면 블록체인 개발에 대한 전문 지식이 없어도 쉽게 컨소시엄 블록체인 네트워크를 구축하고 토큰을 발행, 운영할 수 있습니다.

루니버스 체인

루니버스 체인은 파트너들 모여 분산화된 네트워크 구성합니다. 각 개발사들은 루니버스를 통해 간편하게 자신의 체인을 만들고 루니버스 체인 내의 다른 체인들에 쉽게 deploy 및 transaction 발행할 수 있습니다.

루니버스 체인을 이해하기 전에 3가지 종류의 체인에 대해 이해할 필요가 있으며, 루니버스 체인, 컨소시엄 블록체인, 프로턱트 체인이 바로 그것입니다.

먼저, 루니버스 체인은 전체 블록체인 네트워크를 포함하는 개념이며, 루니버스의 블록체인 위에서 여러 개발사들의 블록체인 네트워크가 운영되며, 여러 블록체인 사이의 인터페이스를 만들어 주어 여러 블록체인 네트워크 사이에서 통신이 가능하게 해줍니다.

다음은 컨소시엄 블록체인인데, 루니버스를 통해 블록체인을 개발하는 개발사들은 루니버스 체인 위에 자신만의 별도의 컨소시엄 블록체인을 구축할 수 있습니다. 루니버스 체인은 이러한 여러개의 컨소시엄 블록체인들을 이어주는 역할을 수행합니다.

마지막으로 프로덕트 체인 이 있는데, 이러한 프로덕트 체인 위에서 실제적인 Dapp 과 Token이 운영되게 됩니다. 각 개발사들은 자신들의 컨소시엄 블록체인 위에 다수의 프로덕트 체인을 구축하여 운영하거나 혹은 루니버스 체인 위에 바로 자신만의 프로덕트 체인을 구축하는 방식으로 서비스를 운영할 수 있습니다.

루니버스에서 프로덕트 체인은 아이콘과 협력하여 만들어지고 있으며, 12월에 정식으로 루니버스 체인의 메인넷이 가동될 예정입니다.

뿐만 아니라 루니버스 네트워크는 이더리움, 이오스 등 다른 대형 블록체인 네트워크 와의 인터페이스를 구축할 예정으로 루니버스 내의 블록체인을 다른 거대 메인넷과 손쉽게 연동할 수 있는 다리 역할을 해줄 것으로 기대됩니다.

종합하자면, 루니버스는 일종의 sass 로 볼 수 있으며, 블록체인 기술을 추상화 시켜 개발자들이 비즈니스 로직에만 집중하여 블록체인 서비스를 만들수 있게 해줍니다.

블록체인과 루니버스의 활용

현시점에서 블록체인 기술은 블록체인 인프라에 그 관심이 집중되었습니다. 이더리움, 이오스 등 계속해서 새로운 블록체인 메인넷들이 출시되었으며, 해당 메인넷 위에서 다양한 서비스가 운영되기 보다는 우수한 메인넷 자체를 개발하는 것에 전 세계의 관심이 집중되었습니다.

즉, 이제까지의 블록체인산업은 블록체인 인프라에 집중되었다고 볼 수 있습니다.

하지만, 과거 산업의 발전 행태를 볼 때 현 시점에서 가장 중요한 것은 바로 블록체인을 활용한 킬러앱의 출시가 블록체인 인프라의 발전방향을 결정짓는 다고 볼 수 있습니다. 가령 인터넷이 처음 나왔을때 인터넷 상의 전자 상거래 서비스 혹은 각종 게임의 발전이 인터넷 산업과 인프라의 발전을 가속화한 것처럼 블록체인 기술을 활용한 상용적인 서비스가 계속 생겨나야 블록체인 인프라도 그에 발맞추어 발전할 전망입니다.

블록체인에서의 게임 산업

루니버스는 블록체인의 여러 산업방면에서도 게임 산업 에 상당한 관심을 가지고 있습니다. 현재 블록체인 기반의 게임산업의 규모는 빠르게 성장하고 있으며, 크게 다음과 같은 3가지 활용처가 존재합니다.

게임의 블록체인화

  1. 인게임 재화 ⇒ fungible token
  2. 아이템 경재 ⇒ non fungible token
  3. 게임의 규칙 ⇒ smart contract

이미 블록체인 기반의 다양한 게임들을 성공리에 운영되고 있는데, 게임회사 뿐 아니라 게임 스트리밍, 게임 마켓 등 다양한 게임 관련 산업분야가 성장하고 있습니다.

블록체인 게임 사례

  • eos 기반의 한 방치형 rpg 게임
    인게임 상에서 재화를 획들할 수 있고 이를 게임 내에서 다시 소비하는 방식으로 토큰 이코노미가 만들어짐
  • 이더몬
    각 사이트를 10명의 유저가 호스트가 되어 공동 소유할 수 있고 일반 유저는 입장료를 내고 탐험하는 방식의 새로운 비즈니스 모델을 선보였으며, 입장료 중 90%는 호스트에게 돌아가고 나머지는 개발자에게 돌아가는 방식으로 운영
  • 게임 스킨
    사용자와 디자이너가 각종 게임 스킨을 만들고 이를 여러 게임에서 사용 가능 => 게임 스킨은 조단위 시장을 형성
  • 토너먼트 형 게임
    좋은 아이템을 구매해서 경기에서 승리하여 상금을 얻는다 => 게임을 통한 수익창출을 위한 기회 비용으로 아이템을 구매한다.

루니버스는 무엇을 해결하는가?

크립토 키티의 경우 메타마스크를 통해 로그인하면서 이탈되는 유저가 전체의 99%에 달할만큼 편리한 유저 인터페이스의 필요성이 대두되고 있습니다. 루니버스는 간편한 사용자 경험을 제공하여 손쉽게 블록체인 서비스를 이용할 수 있도록 할 것입니다.

또한, 기존의 메인넷에서 게임을 하기 위해 필요한 막대한 거래 비용을 게임산업 발전을 저해하고 있으며, 루니버스는 0에 가까운 트랜잭션 fee를 지향하여 서비스를 만들고 있으며, 거래 비용을 줄여 게임에 진입장벽을 낮추어 줍니다.

또 무엇을 제공하나요?

기업 운영

  1. 투자자 네트워크 연계
  2. 올비트 상장 패스트 트랙
  3. 글로벌 마케팅
  4. 공동 PR 진행 및 지원

편리한 개발 프로세스

루니버스 이전의 개발 프로세스에서는 프라이빗 체인 구축 및 디앱개발 및 웹3 작성 및 배포등 일련의 과정에 몇달의 기간이 소요되지만 루니버스를 통한 개발 프로세스에서는 30분 내에 체인을 만들고 토큰을 발행할 수 있습니다. 체인 생성 및 토큰을 버튼 몇번으로 생성하고, 이를 rest api 를 호출함으로써 편리하게 개발이 가능합니다.

개발 프로세스

  1. 메인 체인 만들고 메인 토큰 발행
  2. 프로덕 체인 구축
  3. 메인 토큰과 매칭 되는 프로덕 토큰 발행
  4. 트랜잭션 정의
  5. REST api 를 call 함으로써 서비스 구현

가상화폐 지갑

비트베리와 협업하여 안전하고 편리한 가상화폐 지갑을 제공합니다.

편리한 암호화폐 상장

Allbit Alliance Program ⇒ 루니버스를 이용하기 전의 플로우

  1. 토큰 경제 설계, 백서 검토
  2. 파운데이션 컨설팅
  3. 리갈 펀드 매칭

현재 암호화폐 거래소의 문제였던 과도한 리스팅 비용, 복잡한 절차, 리스팅 네트워킹, 리스팅 사후 관리(가격 방어, 거래량 확보) 를 해결해주고, 루니버스 이용하여 서비스를 개발하여 탈중앙화 거래소인 올비트와 협력하여 간편하게 리스팅이 가능합니다.

또한 올비트가 제공하는 머미넷, 비트 고수, cmt group, Dr. Node&mainblock 등을 통해 리스팅 후의 마케팅 까지 지원합니다.

[ Opensource Blockchain Engine, IT-CHAIN] 04. Authentication

Open Source Blockchain Engine인 It-chain 의 네번째 포스트입니다.

이번 포스트에서는 IT-CHAIN에서 블록의 인증과정에 대해 알아보겠습니다.

어떻게 노드들의 신분을 인증하는가?

모든 노드는 각자 고유의 private key와 public key를 발행하며 이는 it-chain의 자체 라이브러리인 heimdal을 통해 이루어 집니다. heimdal를 통해 키를 생성하면 private key 와 public key 두 쌍의 키가 생기게 되는데, 여기서 public key를 활용하여 각 노드들의 id를 만들어 노드들의 신분을 보장하며, 각 노드는 트랜잭션을 발행하는 시점에 해당 트랜잭션을 자신의 private key로 sign한 signature를 함께 동봉합니다.

트랜잭션의 Signing

트랜잭션을 발행할 때 TX와 함께 signatature를 동봉하게 되는데 이는 보내는 사람의 private key로 sign한 정보이다.

It-chain: https://github.com/it-chain/engine

Opensource Blockchain Engine It-chain 시리즈

LNH

[ Opensource Blockchain Engine, IT-CHAIN] 03. IVM Component

Open Source Blockchain Engine인 It-chain 의 세번째 포스트입니다.

이번 포스트에서는 IT-CHAIN에서 Smart Contract 의 배포와 실행을 담당하는 IVM COMPONENT에 대해 알아보겠습니다.

It-chain의 IVM Component

It-chain 에서는 icode라 불리는 smart contract을 배포할 수 있으며, It-chain 위에서 일어나는 Transaction 이 내포하는 의미는 바로 어떤 노드에서 어떤 smart contract의 어떤 함수를 실행시켰는가에 관한 정보이며 그 구조 중 일부는 다음과 같습니다.

1
2
3
4
5
{
icodeId: _icodeid,
type: invoke | query
function: _functionName
}

여기서 트랜잭션을 실행시킨다는 것은 해당하는 icode 에게 특정 요청을 전달하는 것입니다.

transaction의 종류에는 invoke와 query가 있는데, 여기서 invoke는 데이터를 쓰는 작업이고 query는 데이터를 읽는 작업이라고 볼 수 있습니다. 각 아이코드는 특정 함수에 대한 handler를 가지고 있으며 특정 함수를 실행하면 그에 매칭되는 핸들러가 동작하여 아이코드 내에서 일련의 작업이 일어나게 됩니다.

Icode 들은 어디에 저장되나요?

각 노드에서 배포된 Smart contract인 icode 들은 자신의 고유값을 기준으로 한 git repository에 자장되며, 어떤 노드에서 특정 icode를 실행하기 위해서는 git repository에서 해당 icode 를 받아와서 자신의 노드에 docker container를 구축하여 그 내부에서 icode를 실행시킵니다.

즉, 새로운 스마트 컨트랙이 생성되면 이는 특정 git repository 로 업로드되고 사용되기 전까지 해당 git repository에 저장되어 있습니다.

Docker Container 관리를 위한 Tesseract Library

블록체인 노드에서 여러개의 icode 가 하나의 노드에서 실행되어야 하며, 각 icode는 서로에게 독립적으로 작동하기 위해서 각 icode가 실행되는 환경을 가상화하여 독립시킬 필요성이 생기게 되었으며, 이를 해결하기 위해 it-chain 에서는 리눅스 컨테이너 기술인 Docker 를 사용하게 됩니다.

Docker 란 하나의 노드에서 여러개의 독립 실행 환경을 구성해 줄 수 있으며, 각 실행환경을 Container라는 단위로 부릅니다.

IVM에서 각 icode는 각각 저마다의 독립된 실행공간인 Container 를 가지며 it-chain에서는 각 컨테이너를 생성하고 관리하는 별도의 라이브러리인 Tesseract 라는 독자적인 라이브러리를 사용하고 있으며, Tesseract 라이브러리는 각 컨테이너의 DB에 데이터를 저장하고 출력하는 작업을 수행합니다.

Smart Contract 작성을 위한 SDK Library

Smart Contract 이란 사용자가 특정 함수나 요청을 전달하였을 때 항상 동일한 결과를 내놓는 일종의 블랙박스라고 볼 수 있습니다. icode는 docker위에서 동작하며 위의 invoke 등을 처리함에 있어 sdk의 함수들을 사용하는데 여기서 sdk는 ivm의 tesseract에게 grpc 통신을 통해 데이터를 쓰고 읽는 작업을 처리합니다.

Icode 는 언제 실행되나요?

먼저, icode 의 각 함수는 transaction을 만들어내고 이 tx는 리더에게 전달됩니다.

리더는 tx를 받아 블록을 만들고 해당 블록을 받아 내부에 있는 tx를 실행시킴으로서 실제 icode 가 실행이 됩니다.

현재 잇체인 팀은 계속해서 icode의 실행의 유효성을 보장하기 위한 다양한 시도들을 하고 있습니다.

가령, 현재 it-chain은 transaction 내의 임의 함수로 인해 각 노드에서 다른 결과가 나오는 등 노드 별로 같은 결과값을 가지고 공유하기 위한 연구와 시도등이 있으며, it-chain 팀은 이를 해결하기 위해 각 노드에서 생성된 블록의 transaction 들을 바로 실행시키고 반영하기 전에 미리 한번 각 transaction을 실행시킨 뒤 상대방이 실행시킨 결과값과 나의 결과값이 일치할 때에만 icode 를 실행시키는 등의 장치를 구현중에 있습니다.

스마트 컨트랙의 실행과 World State Database

실행된 스마트 컨트랙트는 각 노드의 상태를 변경시키고 변경된 상태들에 각 컨테이너가 접근할 수 있어야 하기에 공용으로 사용할 상태값 저장 공간이 필요하게 되었으며 이를 World State Database 라고 부릅니다.

it-chain에서 world state database 는 키밸류 DB 인 Level DB를 사용하여 구현되었습니다.

이번 포스트에서는 It-chain 내에서 Smart Contract을 배포 및 실행, 관리하는 IVM Component에 대해 알아보았습니다.

다음 포스트에서는 it-chain에서 노드의 인증을 담당하는 Authentication에 대해 알아보겠습니다.

It-chain: https://github.com/it-chain/engine

Opensource Blockchain Engine It-chain 시리즈

LNH

블록체인 ‘기술’은 무엇인가요

가상화폐에 대한 관심이 높아지면서 많은 사람들이 블록체인 기술에 대해 이야기합니다. 누군가는 새로운 화폐경제의 도래에서 블록체인의 의미에 대해 열변을 토하며 진정한 의미의 경제의 민주화를 이야기하고, 누군가는 단순한 투기의 대상으로써 일확천금을 기대하며 인생역전의 기회에 대해 이야기 합니다.

하지만, 가상화폐는 블록체인 기술의 막대한 활용처 중 일부에 불과하며, 진정한 의미에서 블록체인 기술이 가지는 사회 경제적 의미를 알기 위해서는 블록체인의 ‘기술’ 그 자체로서의 의미와 역사에 대한 이해가 반드시 수반되어야 할 것입니다.

이번 글에서는 ‘가상화폐’를 넘어 블록체인 ‘’기술’ 자체에 주목하여, 기본적인 기술 철학과 개념에 대해 이야기해 보고자 합니다.

블록체인 기술은 무엇을 해결하고자 하는가

현대 사회에서 일어나는 모든 일들은 사실 개인과 개인 사이의 약속과 합의에 관한 문제를 다룬다고 보아도 무방할 것입니다.

인간은 사회적 동물로써 최대 다수의 최대 행복을 추구하기 위한 수많은 사회적 계약을 체결하였고, 현대 사회의 윤리와 법 비즈니스는 이런 사소한 약속들의 집합체에 불과한 것입니다.

이렇게 인간 사회에서 약속과 계약, 거래라는 것이 중요해 짐에 따라 이를 보다 효율적으로 수행하기 위한 수많은 방법들이 도입되었는데, 과거 조개 껍데기가 화폐로 쓰이던 시절부터 오늘날의 주주 명세서에 이르기까지 개인과 개인부터 국가 단체 사이의 거래까지 모든 계약의 신뢰를 보장하고 많은 사람들이 합의를 이루기 위한 각종 형태의 매개물이 생겨나게 되었습니다.

블록체인 기술이 본질적으로 해결하고자 하는 문제도 이와 같은 사회적 의미를 가지며, 그 본질적인 원리는 고대 그리스에서 사회적 합의를 도자기 조각에 적어서 투표를 하던 것 그 이상도 이하도 아닙니다. 다만 물리적인 한계로 과거에는 소수의 사람들만이 도자기에 의사를 적어 선별된 소수끼리만 합의를 이룰 수 있었던 반면, 현대에는 분산 컴퓨팅과 네트워크 속도의 향상 등의 기술적 진보를 통해 이 과정이 과거에 비교할 수 없이 빨라졌으며, 이를 통해 일부의 선별된 집단의 구성원만이 아니라 모든 사람들의 의사를 효과적으로 반영할 수 있는 합의 시스템이 만들어 지게되었는데, 그것이 바로 블록체인 기술이 주는 핵심적인 의미입니다.

즉, 기술의 발전으로 수천 수만의 사람들이 서로간에 완벽하게 투명하게 의사를 교환하고 수렴에 이를 수 있게 된 것입니다.

하지만, 막대한 컴퓨팅 기반으로 수많은 거래와 계약을 모두가 인정하는 합의를 이루는 데에는 과거에는 없던 새로운 문제가 발생하게 되었는데 그것은 바로 모든 거래와 계약의 순서를 올바르게 지키는 것입니다. 수억대의 컴퓨터가 각각의 계약과 거래를 체결하고 이를 모든 컴퓨터와 공유함에 따라 어떤 계약이 먼저 일어났는지를 올바르게 유지하는 것은 매우 어려운 일이며 이를 해결하기 위한 다양한 시도들이 진행되었습니다.

이처럼 블록체인 에서는 위에서 수많은 거래, 계약들이 발생하게 되고, 그 모든 활동을 트랜잭션(transaction) 이라고 부르며, 그 순서와 신뢰도를 보장하여 수많은 컴퓨터들이 합의에 이르도록 해 주는 합의 알고리즘을 필요로 합니다.

합의 알고리즘

블록체인 내에서 일어나는 트랜잭션의 진실여부와 올바른 순서로 일어났는지에 대한 합의를 이루는 방법을 합의 알고리즘 이라고 합니다. 사실 블록체인이 생겨나기 전에는 이러한 모든 합의를 거대한 중앙기관(가령 은행이라는 통화 거래의 중심점) 에게 위임하고 그들이 판단하는 것을 진실로 약속하여 문제를 해결해 왔지만, 블록체인은 이러한 거대 기관이 아닌 진정한 의미에서의 민주주의라는 철학적 관점으로 모든 사람들의 합의를 진실로 규정하고자 하기에 이를 수행하기 위한 합의 알고리즘의 중요성이 강조됩니다.

블록체인의 성능

그렇다면 어떤 블록체인이 우수한 블록체인이라고 불릴 수 있을까요?

블록체인의 성능을 이야기 함에 있어 우리는 TPS(초당 트랜잭션 처리량) 에 대해 이야기 하며, 구체적으로 보자면 블록체인에서 하나의 블록에 속하는 트랜잭션의 수를 그 블록이 생성되는데 걸리는 시간으로 나눈 값으로 이해하면 됩니다. 하지만 이것은 불확실한 정의이며, 가령 특정 블럭이 생성된 이후에 블록이 폐기된다면 해당 트랜잭션은 무효처리 되는데 이 빈도가 많고 적음에 따라 실질적인 TPS를 따지는 데 영향을 미치게 됩니다.

얼핏 생각하면 블록은 어차피 컴퓨터가 만드는 것이고 단순히 임의로 블록을 빠르게 만들어 내도록 하면 더 빠르게 거래가 이루어 질 수 있다고 생각될 수 있습니다.

하지만, 여기서 생각해보아야 할 문제가 있는데 그것은 바로 컴퓨터 사이의 통신 속도입니다.

가령 1억대의 컴퓨터가 있고, 어떤 컴퓨터에서 거래가 일어나 그 거래가 가장 멀리 떨어진 노드에 전파되는 속도가 블록이 생성되는 속도에 비해 너무 길다고 생각해 봅시다. 그렇다면 어떤 거래에 대한 내용을 모든 네트워크 구성원이 인지하기도 전에 거래가 승인되고 그런 거래는 그 신뢰도에 문제가 생기게 될 것입니다. 때문에 전체 네트워크를 구성하는 노드들 사이에서 신뢰를 획득할 수 있을만큼 트랜잭션의 전달(propagation)하는 시간이 주어져야 하며 그 시간보다 블럭이 생성되는데 걸리는 시간이 길어야 신뢰할 수 있는 블럭을 생성할 수 있습니다.

어떻게 블록체인의 성능을 향상시킬 것인가?

그렇다면 어떻게 블록체인의 성능을 향상시킬 수 있을까요?

블록체인의 성능을 향상시키는 방법에는 다음과 같이 크게 3가지 방법이 있습니다.

  1. 샤딩
  2. 사이드 체인
  3. 스테이트 채널

먼저 전체 네트워크에서 특정 거래가 전파되는 속도를 향상시키기 위해서 네트워크를 작게 나누는 방법을 생각할 수 있습니다. 가령 어떤 학교에서 합의를 이루어야 하는 내용을 각 반별로 합의를 이루는 것으로 축약하고, 각 반의 구성원을 특정 숫자 이상으로 유지한다면 어느정도 믿을만한 합의가 이루어질 것인데, 이것을 블록체인에서는 샤딩 이라고 합니다.

현재 이더리움 재단에서 이러한 샤딩을 추진하고 있으며, 누구나 합의 과정에 참여 가능하도록 하자라는 철학을 가지고, stateless client(full state를 들고 있지 않고, state root 및 트랜잭션 정보만을 가진 노드) 도 검증을 수행할 수 있게 하였으며, 트랜잭션에 witness라는 값을 두어서 어떤 노드가 변경이 일어나는지를 추가합니다.

즉, 샤딩은 블록체인 네트워크를 쪼게어 각각 순서를 정하여 합의를 이루고 나중에 합치는 방식으로 네트워크 속도를 향상시킵니다.

다른 방법으로는 어떤 대규모 블록체인 안에서 소규모의 체인을 독자적으로 형성하고 그들사이의 합의 내용을 대규모 블록체인에 전달하는 방식이 있는데 이것을 사이드 체인 이라과 합니다. 이는 마치 중앙 정부와 시민 자치단체의 예로써 설명될 수 있는데, 시민 자치단체의 일정 수 이상의 구성원들이 완벽하게 합의를 이룬 사항에 대해 중앙 정부에 전달하고 이에대한 합의를 진행한다면, 전체 사회 내에서 시민단체에 속한 사람들 사이의 완벽한 합의를 도출하고 그 결과를 중앙정부에 합리적이고 투명하게 전달할 수 있게 될 것입니다.

세번째 방식인 스테이트 채널은 거래 당사자들끼리 합의를 이루고 그 정보를 전체 체인에 올리는 방식입니다.

이처럼 위 방법들은 네트워크를 쪼개어 순서 문제를 해결하고 propagation 속도를 높여 성능을 증가시키고자 하지만, 이 경우 전체 네트워크를 구성하는 노드가 적어지기 때문에 거대 네트워크일 때보다 그 신뢰도가 내려가고 여러가지 문제가 발생할 수 있는 단점이 있습니다.

블록체인에서 거래는 언제 확정되는가

흔히 사람들이 블록체인은 안전하지만 아직 너무 느리다는 이야기를 듣고는 하는데, 일반적으로 거래는 일어나는 즉시 블록체인에 기록하고 합의를 진행하는데 그것이 그렇게 오래 걸리나 하는 의문이 드는 것은 매우 당연한 일입니다.

과거 은행들이 개인의 거래를 누군가와의 합의 없이 자신들의 내부 DB의 정보만을 바꾸는 것으로 거래를 수행하던 것과는 달리 블록체인은 모든 사람의 거래 내역을 하나의 거대한 줄기인 블록들의 체인에 기록하는 것으로 합의가 올바르게 이루어 지지 않는 경우 하나의 줄기가 계속해서 여러 갈래로 나뉘고 다시 합쳐지는 것을 반복합니다. 즉, 이미 일어난 거래라도 블록이 나뉘고 합쳐지는 과정에서 소실될 수 있는 확률이 생기는데, 이는 화폐의 거래에는 매우 큰 이슈입니다. 때문에 블록체인을 통해 화폐를 거래하는 현대의 많은 체인들의 경우 여러 특정 거래가 나뉘지 않고 큰 하나의 줄기로 이어질 확률인 finality 라는 개념을 사용하며 finality 가 낮을 수록 거래가 확정될 확률이 높다고 보며, 비트코인에서는 이러한 finality를 위해 블록이 현재 거래가 발생한 시점부터 6개 이상이 생겨나게 되면 finality가 0.02 이하이기 때문에 확정된 거래로 보고 있습니다.

잘 생각해 보면 이러한 finality는 TPS 속도에 무관함을 알 수 있는데, 거래가 아무리 빨리 일어난다고 하더라도 그만큼 믿을만한 블록들이 생겨나는것은 다른 문제이기 때문입니다. 가령 TPS가 아주 높은 블록체인에서 거래를 하더라도 거래가 빠른 만큼 블록들이 많이 생겨야 finality가 특정 수치 이상으로 낮아질 것이고, TPS가 낮은 블록체인에 비해 더 많은 블록들이 생겨나야 거래가 확정될 수 있습니다.

이러한 finality 를 빨리 단축시키는 방법, 즉 이상적으로 즉시 결제가 일어나기 위해서 많은 방법들이 시도되고 있으며 그 활용 현황은 다음과 같습니다.

  1. finality를 확보하지 않고 거래를 승인
  2. DAG 알고리즘
    블록이 아닌 트랜잭션의 유효성과 순서를 승인 받음
  3. 갈라진 두개의 블록을 병합하는 방식 -> 연구중

첫번째 방식을 사용하는 대표적인 사례는 비트코인 캐시가 있습니다. 비트코인 캐시는 트랜잭션을 받자마자 바로 순서를 인정하며 사용자의 지갑의 값을 변경하는 것으로 즉, finality가 확보되지 않은 상태에서 거래가 진행이 되며 추후 이것이 바뀌면 지갑에서 값이 바뀔 수 있는 문제가 있습니다.

두번째 방식은 DAG 알고리즘을 활용하는 것입니다. DAG 알고리즘에서는 블록단위로 거래를 기록하는 것이 아닌 트랜잭션 단위로 거래를 기록하기 때문에 사실상 실시간으로 거래가 일어날 수 있습니다. 블록체인이 하나의 큰 줄기를 만들어 역사를 기록하는 반면 DAG는 복잡한 거래를 DAG 그래프의 확장으로 보고 모든 노드는 자신에게 관련이 있는 거래만을 가지고 거래를 직접 검증하며, 이경우 블록의 합의 라던가 하는 부분이 이루어 지지 않기 때문에 사실 블록체인으로 보기는 힘든 측면이 있습니다.

세번째 방식은 갈라진 두개의 블록을 병합하여 하나의 블록의 만드는 방식으로 국내 decipher라는 블록체인 학회에서 연구가 진행중에 있습니다.

블록체인의 트랜잭션이 다루는 정보

블록체인이란 기본적으로 transaction으로 인해 변경되는 state를 기록하는 state machine입니다.

여기서 state의 종류에 따라 다양한 state model이 있는데, 다음과 같이 3가지 종류로 구분이 가능합니다.

  1. UTXO(Unspent Transaction Output)
  2. Account
  3. Memory

먼저 UTXO state model은 비트코인이 쓰고 있는 모델로 트랜잭션의 아웃풋 자체가 토큰이고 토큰을 사용하였는가 안하였는가를 현재의 상태로 보고, 이것이 다른 트랜잭션의 인풋으로 들어가면 소비가 된 것으로 봅니다.

Account 모델에서 모든 state는 account에 종속되어 있습니다. 각 account는 자신만의 고유의 nonce 를 가지며, 해당 account의 public key가 키값으로 사용된다. 즉 트랜잭션의 내용은 어떤 account가 가진 잔고에 대한 정보가 되며 이러한 수많은 계정 내역으로 블록체인이 이루어 진다. 이 경우 누가 얼마를 가졌는지를 바로 알 수 있기 때문에 편리한 점이 있지만, 프라이버시 부분에서 좋지 못한 부분이 있습니다.

마지막 모델은 memory 모델인데, 이 경우 트랜잭션은 256비트 짜리 address를 다루며, 각 컨트랙트는 특정 주소값을 할당받고, 여기서 트랜잭션이란 해당 주소값을 변경하는 내용을 기록합니다. 여기서의 키는 각 컨트랙트의 주소가 되며 현재 이더리움 재단에서 이러한 memory 모델과 account 모델을 차용하여 사용하고 있습니다.

블록체인은 어떻게 정보를 저장하는가

블록체인은 사실 블록들의 연결에 불과하고 모든 블록은 컴퓨터에 저장됩니다.

그렇다면 블록체인은 우리 컴퓨터에 어떤 정보들을 어떻게 저장하고 있을까요?

블록체인은 크게 다음과 같은 3가지 정보를 저장하고 있습니다.

  1. state
  2. transaction
  3. result of transaction

위에서 알아본 바와 같이 블록체인은 상태값을 기본으로 저장합니다. 비트코인의 경우 트랜잭션만 저장하고 읽기 작업은 알아서 수행하는 반면 이더리움의 경우는 트랜잭션이 완료된 후의 현재 상태도 저장을 하여 보다 빠르게 데이터를 읽어 올 수 있게 합니다.

위와같은 정보는 대부분의 블록체인에서 키와 밸류 쌍으로 저장되며, 복잡한 쿼리문을 통해 정보를 읽는 등의 기능이 필요하지 않고 단순히 정보를 저장하고 꺼내오는 역할만 수행하므로 가벼운 데이터베이스인 키밸류 db를 사용하며, 흔히 leveldb 를 사용하고 있습니다

LNH

이 저작물은 크리에이티브 커먼즈 저작자표시-비영리-변경금지 4.0 국제 라이선스에 따라 이용할 수 있습니다.

[ Opensource Blockchain Engine, IT-CHAIN] 02. Blockchain Component

Open Source Blockchain Engine인 It-chain 의 두번째 포스트입니다.

이번 포스트에서는 IT-CHAIN에서 블록의 합의를 담당하는 Blockchain component에 대해 알아보겠습니다.

It-chain의 Blockchain Component

블록체인에서 일어나는 모든 거래는 Transaction이라고 불리며, 하나의 블록은 여러 Transaction들의 집합으로 구성됩니다.

때문에 블록체인에서는 생성된 블록이 올바른 블록인지 확인하고 체인에 추가하는 과정이 필요하며, 이 과정은 It-chain의 Blockchain Component에서 이루어 집니다.

또한, It-chain에서는 블록의 저장 및 조회를 위한 별도의 라이브러리를 구현하였으며, Blockchain Component는 yggdrasill에서 정의한 interface에 맞게 구조체를 구현한다면 yggdrasill에 block을 저장, 조회할 수 있습니다.

yggdraill에 연속적으로 저장된 block들을 우리는 blockchain이라고 부릅니다.

Block 의 상태

Blockchain Component에서 Block은 다음과 같은 상태로 존재합니다.

Block State Description
Created 합의되지 않았고, blockchain에 저장되지 않았다.
Staged 합의되었지만, blockchain에 저장되지 않았다.
Committed 합의되었고, blockchain에 저장되었다.

위에서 언급한 바와 같이 블록체인 네트워크를 구성하는 노드들은 계속해서 새로운 블록들을 합의하는 과정중에 있고 합의가 완료되며 오직 리더 노드 에서 블록을 생성하여 다른 노드들에게 전파하고 블록을 받은 노드는 자신이 생성한 블록과 비교하여 검증여부를 판단합니다.

즉, 각 노드에서 막 생성된 블록은 Created 상태에 있으며, 이 블록을 Consensus 알고리즘을 통해 합의를 이루고 합의가 완료되며 Staged 상태로 바뀌게 됩니다.

Staged 상태의 블록이 실제 yggdrasill 내의 데이터베이스에 저장된다면, 블록은 Commited 상태로 변경됩니다.

노드 사이에서 블록의 동기화

동기화(Synchronize)는 특정 노드의 블록 체인을 네트워크 내 임의의 노드의 블록 체인과 동일하게 만드는 과정을 의미합니다.

동기화(Synchronize) 과정의 목적은 모든 블록에 대하여 대표값(Seal), 이전 블록의 대표값(PrevSeal), 트랜잭션 모음(TxList), 트랜잭션 대표값(TxSeal), 블록 생성 시각(TimeStamp), 생성자(Creator), 블록 체인의 길이(Height) 등의 블록 체인과 관련된 모든 정보들을 다른 노드의 것과 같게 만드는 것에 있으며, 이를 통해 블록체인에 참여하는 모든 노드가 같은 블록의 모음을 가지게 될 수 있습니다.

동기화(Synchronize)는 다음과 같이 확인(Check), 구축(Construct), 재구축(PostConstruct) 의 과정을 거칩니다.

확인(Check)

특정 노드의 블록 체인이 동기화가 필요한 상태인지를 점검합니다. 이 과정은 임의의 노드에게 Blockchain 길이와 lastSeal을 받아와서 자신의 블록 체인 정보가 같은 지 비교하여, 동기화가 필요한 상태인지 점검하는 것으로, 이미 동기화가 완료된 상태라면, 동기화(Synchronize) 과정을 중단하고, 그렇지 않을 경우, 구축(Construct) 을 수행합니다.

구축(Construct)

구축에소는 임의의 노드에게 블록 정보를 요청하여, 응답받고, 응답받은 블록을 블록 체인에 저장하는 과정을 반복합니다.

블록 요청은 특정 노드의 블록 체인 길이(Height)를 활용해, 임의의 노드에 블록을 요청함으로써 수행되며, 특정 노드가 새로 참여하는 노드일 경우 임의의 노드의 블록 체인 내 최초 블록부터 마지막 블록까지 요청하고, 기존에 참여중이던 노드일 경우 보유 중인 블록 체인 내 마지막 블록의 다음 블록부터 임의의 노드의 블록 체인 내 마지막 블록까지 요청합니다.

임의의 노드의 모든 블록이 특정 노드의 블록체인에 저장되면 구축(Constrcut)이 완료됩니다.

특정 노드는 구축(Construct) 의 진행 중에 새롭게 합의되는 블록을 블록 임시 저장소(BlockPool)에 보관하며, 구축(Construct) 이 완료되고 나면, 블록 임시 저장소에 블록이 보관되어 있는 지 확인합니다. 보관중인 블록이 있다면, 재구축(PostConstruct)을 수행합니다.

재구축(PostConstruct)

이미 구축(Construct) 된 블록 체인에 블록 임시 저장소(BlockFool)에 보관중인 블록들을 부수적으로 추가하는 것을 의미하며, 재구축(PostConstrcut) 을 수행하고 나면, 동기화(Synchronize) 과정이 모두 완료됩니다.

이번 포스트에서는 It-chain 내에서 블록의 검증과 저장을 수행하는 Blockchain 컴포넌트에 대해 알아보았습니다.

다음 포스트에서는 it-chain에서 dApp을 발행하고 실행하는 ivm 컴포넌트에 대해 알아보겠습니다.

It-chain: https://github.com/it-chain/engine

Opensource Blockchain Engine It-chain 시리즈

LNH

[ Opensource Blockchain Engine, IT-CHAIN] 01. Peer To Peer Network

현재 블록체인 기술은 가장 빠르게 확산되고 있는 유망한 기술 중 하나이며, Bitcoin, Ethereum, EOS 등 수많은 외산 블록체인 엔진들이 입지를 굳혀가는 가운데 국내에서도 블록체인 코어 기술을 위한 많은 연구가 진행이 되고 있습니다.

이번 글에서는 수많은 블록체인 엔진들 중에서도 Lightweight Customizable Chain을 목표로 활발하게 개발이 진행중인 국내 오픈소스 블록체인 엔진인 IT-CHAIN에 대해 살펴보고자 합니다.

본 포스트는 연재 형식으로 IT-CHAIN의 핵심적인 component인 p2p, consensus, blockchain, authentication, txpool, iCode 를 다루는 총 4~6편의 포스트로 이루어 질 예정이며, 오늘은 it-chain의 전체적인 구조와 더불어 그 첫번째 component 인 p2p component에 대한 소개를 하고자 합니다.

What is it-chain?

많은 블록체인 엔진들 중에서 it-chain을 소개하게 된 계기는 무엇보다 구조적으로 매우 직관적이고 이해하기 쉽게 설계되어 있기 때문입니다. 가령, ethereum과 hyperledger처럼 당장 상용화를 목적으로 개발이 진행중인 엔진들은 실용적 문제들에 봉착하여 다양한 기법과 최신 기술을 도입하여 코드를 당장 이해하기 어려움이 있기에 블록체인을 처음 접하는 사람들의 경우 전체 코드를 한눈에 이해하는 것은 매우 어려운 일이 아닐 수 없습니다. 하지만, it-chain은 전체 설계 및 핵심적인 컴포넌트들이 비교적 상세하게 문서화가 되어 있고, 블록체인의 핵심이 되는 기본적인 기능만을 구현하였기 때문에, 블록체인 엔진이 움직이는 큰 그림을 보다 직관적이고 쉽게 이해할 수 있는 장점이 있습니다. 만약 블록체인 엔진 개발에 관심이 있는 엔지니어라면 그 시작으로 it-chain 의 구현을 살펴보는 것을 추천합니다. (it-chain의 github 주소, https://github.com/it-chain/engine)

it-chain이 지향하는 바는 블록체인을 개발하는 누구든지 쉽고 가볍게 커스터마이징이 가능한 엔진을 만드는 것 입니다. 만약 누군가가 ethereum의 코드를 가져다가 자신만의 블록체인 엔진을 만든다고 한다면 그것은 매우 어려운 일일 것 입니다. 합의 알고리즘 하나를 변경하더도 관련된 모든 코드에 대한 이해가 필요하며 얼기설기 얽혀있는 수많은 코드들을 재정리 해야 합니다. 하지만, it-chain 은 event-sourcing을 기반으로 모든 동작이 event를 기반으로 이루어 지기에 다른 구성요소들의 동작에 구애받지 않고 원하는 파트만 손쉽게 변형하여 자신만의 engine을 만들 수 있습니다.

it-chain의 전체 구조

it-chain은 6개의 독립적으로 동작하는 핵심 컴포넌트들로 구현되며, 각각은 AMQP(Asynchronous Message Queue Protocol) 를 통해 커뮤니케이션을 합니다. AMQP는 이벤트 버스로서 각 컴포넌트들에서 일어난 모든 일들은 이벤트 형태로 전파되어 다른 컴포넌트들이 해당 이벤트에 맞는 동작을 수행함으로써 전체 기능이 동작하는 방식입니다.

다음은 it-chain의 각 컴포넌트의 간단한 역할을 보여줍니다.

  • TxPool 컴포넌트: 트랜잭션을 임시로 저장하고 관리하는 컴포넌트로, 합의되어 블록에 저장되지 않은 트랜잭션들을 모아둡니다.
  • Consensus 컴포넌트: 합의를 담당하는 컴포넌트이며, 현재는 PBFT(Practical Byzantine Fault Tolerance) 알고리즘을 따릅니다.
  • BlockChain 컴포넌트: 블록을 생성하고 관리하는 컴포넌트입니다.
  • P2P 컴포넌트: 네트워크의 참여하는 Peer들을 찾고, 유지하는 컴포넌트입니다.
  • Auth 컴포넌트: 각종 인증을 담당합니다.
  • iCode 컴포넌트: it-chain의 스마트 컨트랙트인 iCode 관련 기능을 담당합니다.

It-chain의 Peer to Peer 네트워크

이번 포스트에서는 it-chain에서 여러 노드들 사이의 네트워크 정보를 동기화하고 커넥션을 관리하는 p2p component와 노드 사이의 합의를 이루는 consensus 컴포넌트에 대해 알아보고자 합니다.

먼저, P2p 컴포넌트가 하는 일은 다음과 같습니다.

  • 블록체인 네트워크 내의 다른 노드들의 존재를 인지하고 저장합니다.
  • 네트워크 내의 노드들 사이의 connection정보와 ip 주소 정보를 Peer 라는 이름으로 저장하고 여러 Peer 들의 집합인 PeerTable 을 형성합니다.
  • 모든 노드들이 네트워크 내의 모든 노드들에 대한 정보인 PeerTable 을 공유하고 동기화 합니다.

예를 들어 현재 블록체인 네트워크가 A, B, C 노드로 이루어져있다고 가정해 봅시다.

여기서 D라는 새로운 노드가 A라는 노드에게 접속을 요청을 하게 된다면 D 노드는 A 노드의 정보만을 알고 있게 될 것이며, 마찬가지로 B, C 노드도 D노드에 대한 정보를 알지 못할 것입니다.

하지만 private 블록체인에서는 모든 노드들이 계속해서 서로 통신을 위해 연결되어 있어야 하기 때문에 새롭게 연결된 노드의 정보를 다른 노드들에게 전파해 주어야 하며 각 노드들은 전체 네트워크에 대한 일관된 정보를 공유해야 합니다.

네트워크 정보는 어떻게 저장되나요?

p2p 컴포넌트 내의 연결 정보는 Peer 라는 이름으로 저장이 되며, 그 안에는 특정 노드와의 연결에 대한 고유값인 connectionId와 상대 노드의 ip 주소 를 저장합니다.

가령 A, B, C 노드로 구성된 네트워크가 있다면 A 노드는 B, C 노드와 연결됨에 따른 고유한 connection과 B, C 노드의 ip 주소를 Peer A, Peer B 라는 이름으로 저장하며 모든 노드는 이러한 peer들의 정보를 peer 들의 정보의 집합인 PeerTable 에 저장합니다.

네트워크 정보는 어떻게 공유되나요?

블록체인 네트워크에 새로운 노드가 접속하는 것은 네트워크 내의 특정 노드에게 연결을 요청하는 것에서 시작됩니다.

노드 A, B, C 로 구성된 네트워크에서 D라는 노드가 접속되는 상황을 가정해 봅시다.

노드 D는 A, B, C 노드 중 임의의 노드인 A 노드에게 연결을 요청하고 만약 연결이 이루어 진다면 노드 D의 정보는 노드 A의 PeerTable 에 저장되고, 노드 A 는 새롭게 바뀐 PeerTable 을 노드 D에게 전달해 줍니다.

노드 D는 A에게 받은 PeerTable을 살펴보고 아직 자신이 연결하지 않은 노드인 B와 C 노드에 대해 알게되고 해당 노드의 ip 주소로 연결을 요청하게 됩니다.

B, C 노드가 새로 접근한 노드인 D 노드에게 연결을 요청받고 승인하는 것으로 네트워크 내의 모든 노드는 새로 접근한 노드인 D 노드와 연결이 이루어지게 됩니다.

It-chain의 Consensus 컴포넌트

블록체인에서 핵심은 바로 consensus 입니다.

consensus 컴포넌트는 특정 블록을 생성하기 위해 다른 노드들에게 해당 블록을 생성해도 되는지 검증을 요구하고 네트워크 구성원들의 합의가 이루어지면 새로운 블록을 생성합니다.

It-chain 에서 이러한 합의 알고리즘은 설정을 통해 간편하게 교체할 수 있으며 기본적으로 pbft 알고리즘에 따라 합의가 이루어 지게 됩니다.

pbft 합의 알고리즘

consensus-PBFT

기본적인 PBFT 알고리즘은 다음과 같은 순서로 이루어지게 됩니다.

  1. 클라이언트가 네트워크 구성원에게 어떤 합의문에 대해 합의할 것을 요청합니다.
  2. 합의 요청을 받은 노드들 중 리더 노드는 네트워크 내의 모든 구성원에게 특정 합의에 대한 합의를 시작할 것을 알리는 preprepare message 를 전달합니다.
  3. preprepare message 를 전달받은 모든 노드는 다시 모든 노드에게 prepare message 를 전달합니다.
  4. 전체 네트워크 구성원들 중 정족수(2/3) 이상의 노드에게 받은 preparemessagecommit message 를 모든 노드들에게 전달합니다.
  5. 위 과정이 끝나면 모든 노드들은 정족수이상이 합의한 결과를 가지게 됩니다.

하지만 It-chain 에서는 오직 리더만이 새롭게 생성될 블록을 제안하고 실제로 생성할 수 있으므로 위 과정에서 클라이언트 및 요청 응답이 존재하지 않습니다.

It-chain에서 pbft 알고리즘의 구현

It-chain에서는 위와 같은 pfft 알고리즘 구현을 위해 다음과 같은 몇가지 개념을 도입합니다.

  • Parliament: 의회, 즉, 합의에 참여할 노드들의 집합을 의미합니다.
  • Representative: 대표자, 즉 합의에 참여할 실제 노드 구성원을 의미합니다.
  • Leader: 의장, 즉 의회 구성원의 대표인 리더를 의미합니다.

pbft의 목적은 어디까지나 합의하고자 하는 블록에 대한 합의이기에 다음과 같은 과정에 따라 pbft 기반의 합의 알고리즘이 동작됩니다.

  1. 리더 노드의 consensus 컴포넌트가 블록 생성을 담당하는 blockchain 컴포넌트로 부터 합의하고자 하는 블록을 제안받습니다.
  2. 리더 노드는 해당 블록에 대한 합의를 진행하기 위해 현재 네트워크를 구성하고 있는 정보를 담고 있는 PeerTable 에서 전부 혹은 부분적인 노드를 선출하여 Parliament 를 구성합니다.
  3. 리더 노드가 Parliament 에 속한 모든 Representative 들에게 preprepare message 를 전달합니다.
  4. preprepare message 를 받은 모든 representative 들은 받은 정보를 통해 각자의 Parliament 를 구축하고 다른 Representative 들에게 prepare message 를 전달합니다.
  5. Representative 들은 정족수 이상의 prepare 메세지를 받기 까지 받은 모든 prepare messageprepare message pool 에 저장하고 정족수 이상이 넘으면 commit message 를 전파합니다.
  6. 전체 의회 구성원의 1/3 이상에게 commit message를 받은 각 Representative 들은 Commit message 내의 Proposed Block 에 대한 승인을 하는 이벤트를 발생시키고 블록체인 컴포넌트는 해당 블록에 대한 검증을 시작합니다.
    Proposed Block 이 confirm 되기 까지 Commit message 들은 Commit message pool 에 저장됩니다.

It-chain에서 리더의 선출

it-chain 에서의 리더 선출은 RAFT 라는 알고리즘을 통해 진행되며 consensus 컴포넌트에 구현되어 있습니다.

다음은 RAFT 알고리즘의 간단한 프로세스입니다.

  1. 리더가 사라지면 노드는 의회를 구성합니다.
  2. 150ms ~ 300ms 사이의 랜덤 값으로 모든 노드가 타이머를 동작시킵니다.
  3. 노드의 타이머가 다 되면 그 노드는 자신의 상태를 Candidate 으로 바꾸고 RequestVoteProtocol을 통해 의회 내의 다른 노드에게 투표 요청 message 를 전달합니다.
  4. RequestVoteProtocol 로 메세지를 받은 노드는 아직 타이머가 다 되지 않은 경우 타이머를 리셋하고, 송신한 노드에게 VoteLeaderProtocol을 통해 메세지를 전달하여 리더로 투표합니다.
  5. 만약 상태가 CANDIDATE 인 노드가VoteLeaderProtocol를 통해 다른 모든 노드에게 투표 메세지를 받는다면 그 노드는 스스로 리더가 되고 다른 모든 노드들에게 리더가 됨을 선포합니다.

위와 같은 과정을 통해 물리적으로 떨어져 있는 여러 개의 노드들이 서로 합의를 이루고 리더를 선출 할 수 있게 됩니다.

이번 포스트에서는 국내 블록체인 엔진인 it-chain 의 p2p network 와 consensus 알고리즘, 그리고 리더 선출에 대해 알아보았습니다.

다음 포스트에서는 it-chain에서 블록을 합의하는 컴포넌트인 Blockchain 컴포넌트에 대해 알아보겠습니다.

  • LNH
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×