10. Coinstack Permission

비트코인은 공개된 환경을 지향하여 기본적으로 누구나 트랜잭션을 전송 할 수 있고 풀노드를 운영하거나 마이닝을 시도할 수 있습니다. 하지만, 기업의 프라이빗 네트워크 등 비공개 환경에서 사용할 때에는 제한된 권한을 특정 사용자에게 부여해야 할 필요가 있습니다. 이러한 요구에 따라 코인스택에서는 특정 비트코인 주소에 역할을 부여하여 권한을 제한하는 방법을 제공합니다.

1. 사전 요구 사항

아래와 같은 설정을 사용하는 프라이빗 코인스택의 경우에만 권한 설정 기능을 사용할 수 있습니다. 코인스택 서버의 상세 설정 정보는 코인스택 설치 문서를 참조하시기 바랍니다.

  • privnet=1: 프라이빗 네트워크를 구성합니다. 프라이빗 네트워크인 경우에만 역할 관리 기능을 사용 가능합니다.

  • privnetgenesis={serialized genesis block}: 참여하려는 네트워크의 직렬화된 제네시스 블록(블록 높이가 0인 제일 처음 블록)을 기재합니다. 별도로 제공하는 gengenesis라는 프로그램에 최초의 admin으로 사용할 주소의 개인키를 사용하여 제네시스 블록을 생성할 수 있습니다.

  • privnetnodekey={privatekeyWIF}: 노드에 부여할 개인키로 노드에 고유한 ID를 부여합니다. 각 노드마다 다르게 설정해 주어야 합니다.

2. 개요

프라이빗 코인스택에서는 하나의 비트코인 주소에 총 4가지의 역할을 부여 할 수 있습니다. 주소를 사용하는 주체가 사용자나 어플리케이션 일 경우 AdminWriter 역할을 부여하여 각각 계정관리와 트랜잭션의 쓰기 권한을 줄 수 있습니다. 역할별 상세 설명은 다음과 같습니다.

  • Admin (Authority Manager): 역할을 설정/관리합니다. Admin을 제외한 다른 모든 역할(Writer, Miner, Node)을 활성화/비활성화 할 수 있습니다. 다른 모든 역할의 권한도 가집니다. 즉, 트랜잭션을 쓰고 블록을 생성하고 프라이빗 네트워크에 참여할 수 있습니다.

  • Writer (Transaction Writer): 트랜잭션 생성 및 전송할 수 있습니다. 이 역할이 활성화 되어 있는 경우에 트랜잭션 쓰기 역할이 없는 주소의 개인키로 서명하여 전송한 트랜잭션은 코인스택 노드에서 수용하지 않습니다.

주소를 사용하는 주체가 노드인 경우 MinerNode 역할을 부여하여 노드의 권한을 제한할 수 있습니다. (여기서의 주소는 노드의 설정파일의 privnetnodekey에 기재되어 있는 개인키와 대응하는 주소를 지칭합니다.)

  • Miner (Block Miner): 블록을 생성할 수 있습니다. 이 역할이 활성화 되어 있는 경우에 Miner 역할이 없는 노드가 마이닝한 블록은 다른 코인스택 노드들이 수용하지 않습니다.

  • Node (Network Participant): 이 역할이 있는 노드만 프라이빗 네트워크에 참여할 수 있습니다. 이 역할이 활성화 되어 있는 경우에 Node 역할이 없는 노드는 코인스택 노드에 접속 및 동기화를 할 수 없습니다.

역할을 부여하는 보안상 가장 안전한 방법은 역할별로 주소를 여러개 생성하여 하나의 주소에 하나의 역할만 부여하는 것이지만, 경우에 따라 주소 하나에 여러개의 역할을 부여해야 하는 경우도 있습니다. 예를 들면 Node와 Miner 권한이 활성되어 있는 경우, 주소 하나에 Node 와 Miner 역할을 동시에 부여해서 사용해야 해당 노드는 프라이빗 네트워크에 접속해여 자신이 생성한 블록을 전파할 수 있습니다. 또한 Admin 역할을 가지는 주소는 환경 설정의 편의성을 위해 모든 권한을 가집니다.

참고로 앞서 설명한 스마트 컨트랙트에서의 grant, revoke를 사용한 함수 수행 권한관리는 Admin이 아닌 스마트 컨트랙트를 정의한 주소의 소유자가 설정 가능함으로 유의하시기 바랍니다.

3. 역할 활성화 / 비활성화

가장 처음 코인스택을 구동하여 제네시스 블록만 존재할 때는 위의 역할들 중 Admin 역할만 활성화 되어 있고 하나의 Admin 주소만 존재합니다. 즉, 나머지 역할들(Writer, Miner, Node)은 비활성화되어 있습니다. 이는 초기 환경 구성 시의 편의성과 필요한 기능만 선택적으로 사용 가능하도록 하기 위함입니다.

3.1. 역할 활성화 트랜잭션 생성

역할을 활성화/비활성화 하기위해서는 Admin 권한을 가진 개인키로 SDK에서 제공하는 역할 활성화용 트랜잭션 빌더(EnableRoleBuilder)를 사용하여 트랜잭션을 생성, 네트워크에 전파하면 됩니다. 다음의 예제는 java SDK를 사용하여 프라이빗 네트워크의 Miner, Node 역할을 활성화, Writer는 비활성화 시키는 예제입니다. 참고로 Admin 역할은 항상 활성화 되어 있습니다.

JAVA

// 역할 활성화 트랜잭션 빌더 생성
EnableRoleBuilder enRoleBuilder = new EnableRoleBuilder();
// OR operator를 이용하여 Miner와 Node 두 역할을 지정하는 Role 객체 생성
Role role = new Role(Role.MINER|Role.NODE);
// 역할 객체 할당
enRoleBuilder.setRole(role);
// 트랜잭션 생성, 이 때 개인키는 Admin 역할을 가진 주소의 키를 사용해야 함
String rawTx = enRoleBuilder.buildTransaction(client, ADMIN_PRIVATEKEY);
client.sendTransaction(rawTx);

일반적인 트랜잭션과는 달린 역할 관리에 연관된 트랜잭션들은 해당 트랜잭션이 블록에 포함 된 후 적용됩니다. 또한 Admin 권한이 없는 개인키를 사용한 경우 등 역할 설정 트랜잭션에 문제가 있을 경우 트랜잭션이 블록에 포함됬더라도 설정이 변경되지 않을 수 있습니다. 이 경우 에러 메시지가 서버의 로그에 기록됩니다.

3.2. 활성된 역할 조회

현재 활성화 되어 있는 역할들을 확인해 보려면 다음과 같이 조회합니다.

JAVA

// CoinStackClient에서 현재 활성화 되어 있는 역할 조회
Role currentEnabledRole = client.getEnabledRole();
System.out.println(currentEnabledRole);

앞서 역할 활성화 트랜잭션이 정상적으로 수행된 경우, 수행결과는 다음과 같습니다.

MINER|NODE

REST API

curl http://privnet.cloudwallet.io/roles/enabled

결과 값은 JSON 형식으로 반환됩니다.

{
   "permission": 12
}

REST API로 조회한 경우 결과는 4개의 bit로 표현됩니다. 1(0001)은 Admin, 2(0010)는 Writer, 4(0100)는 Miner, 8(1000)은 Node 권한을 의미합니다. bit의 조합으로 여러권한을 의미할 수도 있는데 예를들면 12(1100)은 Miner와 Node의 권한이 활성화 되어 있다는 의미입니다. 단, Admin은 항상 활성화 되어 있기 때문에 0으로 표기됩니다.

4. 역할 설정

SDK를 이용하여 특정 주소에 역할을 부여하는 방법을 설명합니다.

4.1. 역할 설정 트랜잭션 생성

특정 주소에 역할을 설정할 때는 역할을 설정하는 마커를 가진 데이터 트랜잭션을 이용합니다. 코인스택 SDK에서는 이를 쉽게 지원하기 위한 역할 설정 트랜잭션 빌더(SetRoleBuilder)를 제공합니다. 아래는 SDK를 이용해 특정 주소에 Miner, Node 역할을 부여하고 Admin, Writer 역할을 제거하는 예입니다.

JAVA

// 역할 설정 트랜잭션 빌더 생성
SetRoleBuilder setRoleBuilder = new SetRoleBuilder();
// OR operator를 이용하여 Miner와 Node 두 역할을 지정하는 Role 객체 생성
Role role = new Role(Role.MINER|Role.NODE);
// 역할 객체 할당
setRoleBuilder.setRole(role);
// 역할을 부여할 대상 주소 입력
roleBuilder.setAddress(TARGET_ADDRESS);
// 트랜잭션 생성, 이 때 개인키는 Admin 역할을 가진 주소의 키를 사용해야 함
String rawTx = setRoleBuilder.buildTransaction(client, ADMIN_PRIVATEKEY);
client.sendTransaction(rawTx);

먼저 Role 클래스 생성자에 부여할 역할을 할당합니다. 여러개의 역할을 부여하려면 OR 연산자로 여러 역할을 조합합니다. 그리고 SetRoleBuilder에 Role객체를 할당하고 해당 Role을 부여할 대상 주소를 입력합니다. 그 후 Admin 역할을 가진 개인키를 사용하여 트랜잭션을 생성하여 전송합니다. 해당 역할은 트랜잭션이 블록에 포함된 뒤 모든 노드에 반영됩니다.

Admin은 다른 주소에 Admin 권한을 부여/박탈 가능합니다. 심지어 자기 자신의 권한도 없엘 수 있습니다. 권한 부여는 Set 형식으로 기존의 권한에 추가가 아닌 덮어쓰는 형태이기 때문에 사용에 주의가 필요합니다. 예를 들어 기존의 Admin에 new Role(Role.WRITER) 같이 역할을 할당하면 Admin 권한이 사라지고 Writer 권한만 남게 됩니다.

특정 역할이 비활성화 되어 있어도 특정 주소에 해당 역할을 미리 부여할 수 있습니다. 예를 들면 Node 역할이 비활성화 되어 있어도 노드들의 주소에 미리 Node 역할을 부여할 수 있습니다. Node 역할을 미리 노드들에 부여하지 않고 Node 역할을 활성화 시킬 경우 서로간에 Node 권한이 없다고 생각하고 노드들이 서로 연결을 끊어 블록이 전파가 안되므로 주의해야 합니다. Miner의 경우도 마찬가지로 미리 역할을 부여하고 해당 기능을 활성화 시켜야 마이너가 권한 생성 트랜잭션을 블록에 포함, 전파 시킬 수 있습니다.

4.2. 특정 주소의 역할 조회

특정 주소에 부여된 역할을 조회할 때는 CoinStackClient의 getRole 함수를 사용합니다. 아래는 권한 조희 예입니다.

JAVA

// CoinStackClient에서 특정 주소에 부여되어 있는 역할 조회
Role assignedRole = client.getRole(TARGET_ADDRESS);
System.out.println(assignedRole);

앞서 역할 설정 트랜잭션이 정상적으로 수행된 경우, 수행결과는 다음과 같습니다.

MINER|NODE

REST API

curl http://privnet.cloudwallet.io/roles/{TARGET_ADDRESS}

결과 값은 JSON 형식으로 반환됩니다.

{
   "permission": 12
}

permission 이라는 키에 조회를 요청한 주소의 역할값이 할당되어 반환됩니다.

4.3. 역할이 설정된 전체 주소 조회

현재 역할이 정의된 모든 주소와 각 주소의 역할을 조회해 보기 위해서는 다음과 같이 조회해 볼 수 있습니다.

JAVA

// CoinStackClient에서 역할이 부여되어 있는 전체 주소 조회
Map<String, Role> addressRoleMap = client.listAllRole();
for (Entry<String, Role> roleEntry : addressRoleMap.entrySet()) {
    System.out.printf("%s: %s\n", roleEntry.getKey(), roleEntry.getValue());
}

수행결과는 다음과 같습니다.

133N13JpiWcncKLiNJLDD5yvTxT8tazmc7: ADMIN
18G3MD6RdhpZbAaQiuVpvxedzQK4UmTqWs: MINER|NODE
1NX8A7pxaAr7A3QQtBYVLDaK17jRpzigTP: NODE
...

REST API

curl http://privnet.cloudwallet.io/roles

결과 값은 JSON 형식으로 반환됩니다.

{
   "133N13JpiWcncKLiNJLDD5yvTxT8tazmc7": 1,
   "18G3MD6RdhpZbAaQiuVpvxedzQK4UmTqWs": 12,
   "1NX8A7pxaAr7A3QQtBYVLDaK17jRpzigTP": 8
}

현재 네트워크에 등록되어 있는 전체 역할의 목록이 주소를 키로, 역할을 값으로 하여 반환됩니다.

Last updated