11. Additinal Features

코인스택은 범용적인 블록체인의 개발 API를 제공하지만 더 단순화 된, 혹은 반대로 성능 향상 등을 위해 더 심화된 기능을 사용하고자 하는 요청들이 있습니다. 이러한 것들 중 자주 회자되는 기능들을 모아 SDK에서 이를 지원하는 유틸리티 클래스들을 제공합니다.

1. Easy Transaction Sender Utility

코인스택의 트랜잭션은 비트코인의 표준(Standard)을 따릅니다. 단순한 트랜잭션의 경우 트랜잭션 빌더의 기본 설정으로 트랜잭션을 빌드해도 문제가 없습니다. 하지만 너무 적은 양의 비트코인을 보내려 하거나 너무 큰 사이즈의 트랜잭션을 보내고자 하는 등 예외적인 경우에는 정책상 트랜잭션이 거절 될 수 있습니다. 이에 따라 트랜잭션 빌더에서는 정책적인 부분을 세세하게 설정해 줄 수 있는 API가 존재합니다. 하지만 대다수의 사용자의 경우 표준 형식의 비트코인 트랜잭션의 정책을 숙지하고 있지 않습니다.

또한 앞에서와 같이 트랜잭션을 설정해야 하기 때문에 일반적으로 블록체인에서는 트랜잭션을 전송하기 위해서는 트랜잭션 빌더를 통한 설정, 생성, 코인스택 클라이언트를 통한 전송의 3단계를 거치게 됩니다. 그러나 이에 따른 중복된 코드 사용이 발생하고 코드의 이해도가 낮아지는 경우가 있습니다.

이러한 측면에서 사용자 편의의성을 위해 코인스택에서는 자동적으로 표준 형식에 맞추기 위한 TransactionBuildTip이라는 클래스와, 한 단계로 트랜잭션을 전송 할 수 있는 TransactionSender라는 유틸리티 클래스를 제공합니다.

1.1. Transaction Build Tip

트랜잭션 생성 팁(TransactionBuildTip)은 이후 설명할 TransactionSender에서 표준 트랜잭션을 생성하기 위해 필요한 가이드를 제공합니다. SDK에서는 일반적으로 많이 쓰이는 설정을 모아 다음과 같이 두가지의 팁을 제공합니다.

1.1.1. Standard Tip

일반적인 비트코인 표준 수수료 정책을 따릅니다. 다음과 같은 사전 정의된 정책을 사용합니다.

  • 기본 수수료: 0.00001 btc

  • KB 당 (크기에 따른) 수수료: 0.00001 btc

  • UTXO 최대치 가이드: 100개

기본 수수료는 무조건 하나의 트랜잭션에 할당되는 최소 금액의 트랜잭션입니다. KB당 수수료는 트랜잭션 사이즈가 커짐에 따라 KB당 추가로 부가할 수수료 입니다. UTXO 최대치 가이드는 한 트랜잭션에 Input으로 너무 많은 UTXO를 넣을 경우 트랜잭션 생성에 시간이 오래 걸리므로 최대 해당 개수만큼만 사용하도록 가이드 합니다. 위의 100개를 예로 들면 트랜잭션을 보낼 주소의 UTXO가 100개를 넘을 경우, 트랜잭션의 'output + 수수료'만큼의 비트코인 합계를 가지도록 UTXO를 일부만 선택하여 트랜잭션의 입력으로 넣게 됩니다. 하지만 UTXO 각각의 금액이 작을 경우 100개의 UTXO를 더해도 보낼 총 량보다 적을 경우에는 100개를 넘겨 필요한만큼 입력합니다.

JAVA

TransactionBuildTip standardTip = TransactionBuildTip.STANDARD;

1.1.2. Zero Fee Tip

트랜잭션에 수수료를 항상 0으로 설정합니다. 수수료를 받지 않아도 트랜잭션을 수용하도록 설정된 코인스택 프라이빗 네트워크일 경우에만 사용하기를 권합니다. (코인스택 서버가 다음과 같이 설정되어야 합니다. minrelaytxfee=0, blockprioritysize={블록사이즈와 동일}) 기본 비트코인 정책을 사용하도록 설정된 네트워크에서는 이 팁을 사용해 성성한 트랜잭션은 수수료가 부족하여 블록에 포함되지 않을 수 있습니다.

  • 기본 수수료: 0 btc

  • KB 당 (크기에 따른) 수수료: 0 btc

  • UTXO 최대치 가이드: 10개

JAVA

TransactionBuildTip zerofeeTip = TransactionBuildTip.ZEROFEE;

네트워크가 수수료 0인 트랜잭션을 허용하는 경우 트랜잭션 팁과 샌더를 사용하지 않고 기존 처럼 트랜잭션 빌더를 통해 트랜잭션을 만드는 경우에도 setFee를 통해 수수료를 0으로 설정하여 보내는게 가능합니다.

1.2. Transaction Sender

트랜잭션 샌더는 트랜잭션 설정, 빌드, 전송의 3 단계를 한 단계로 단순화 하여 트랜잭션 전송을 쉽게 할수 있도록 돕는 유틸리티 클래스입니다. 트랜잭션 샌더는 앞서 설명한 트랜잭션 생성 팁을 인자로 입력 받습니다. 다음은 트랜잭션 샌더의 생성 예 입니다.

JAVA

// standard tip을 사용할 경우
TransactionBuildTip txBuildTip = TransactionBuildTip.STANDARD;
// transaction sender 인스턴스 생성
TransactionSender txSender = new TransactionSender(coinstackClient, MY_PRIVATEKEY, txBuildTip);

이렇게 생성한 트랜잭션 샌더를 이용하면 아래와 같은 기능들을 생성자에 입력한 개인키와 트랜잭션 생성 팁을 사용해 쉽게 수행할 수 있습니다.

1.2.1. Send Coin

내 계좌로부터 대상 주소에 입력한 수량만큼의 비트코인을 보냅니다. 아래는 SDK를 이용해 대상 주소에 3 btc를 보내는 예입니다. 한번에 하나의 주소에만 가능하며 잔고가 부족할 경우 실패합니다.

txSender.sendCoin(TARGET_ADDRESS, 3);

1.2.2. Write Data

대상을 지정하지 않은 데이터 트랜잭션을 생성합니다. 스탬핑 등에 사용합니다. 아래는 SDK를 이용해 사용자 데이터(SERIALIZED_DATA_BYTE)를 기록하는 예입니다.

txSender.writeData(SERIALIZED_DATA_BYTE);

1.2.3. Send Data

대상을 지정하는 데이터 트랜잭션을 생성합니다. Openkeychain 등에 사용합니다. 아래는 SDK를 이용해 대상 주소에 사용자 데이터를 기록하는 예입니다.

txSender.sendData(TARGET_ADDRESS, SERIALIZED_DATA_BYTE);

1.2.4. Define Contract

스마트 컨트랙트를 정의합니다. 아래는 SDK를 이용해 대상 컨트랙트 주소에 스마트 컨트랙트를 정의하는 예입니다. 일반적으로 대상 컨트랙트 주소는 트랜잭션 샌더를 생성했을 때 입력한 개인키에서 유추된 주소여야 합니다. 즉, 해당 주소의 소유자이여야 해당 주소에 컨트랙트를 정의 가능합니다.

txSender.defineContract(TARGET_CONTRACT_ID, luaContractDefinitionCode);

1.2.5. Execute Contract

스마트 컨트랙트를 수행합니다. 아래는 SDK를 이용해 대상 컨트랙트 주소에 스마트 컨트랙트를 수행하는 예입니다. 컨트랙트 수행은 정의와 달리 어떠한 주소도 가능합니다. 이를 제한하기 위해서는 앞서 설명한 스마트 컨트랙트 권한 grant 기능을 참조하시기 바랍니다.

txSender.executeContract(TARGET_CONTRACT_ID, luaContractExecutionCode);

2. Special NullData: Address-Data

코인스택에서는 Openkeychain과 스마트 컨트랙트 등 OP_RETURN으로 데이터를 보낼 시 특정 주소에 600 사토시를 보내는 트랜잭션 아웃풋(dusty 아웃풋)을 추가해 대상 주소(e.g. 수행 대상 스마트 컨트랙트, 인증서 발급 주소)에 이력을 남기고 있습니다. 이렇게 하는 이유는 한 트랜잭션에는 하나의 Null Data 트랜잭션 아웃풋만 허용되기 때문입니다. 하지만 이로 인해 트랜잭션을 쓰기위해 600 사토시가 계속 소모되고, 상대방의 주소에는 사용 불가능한 UTXO가 지속적으로 쌓이게 됩니다.

이러한 이슈를 해소하기 위해 코인스택에서는 Address-Data라는 현재 트랜잭션을 받는 대상을 표현하는 Null Data를 제공합니다. 트랜잭션에 Address-Data로 대상 주소를 설정하면 대상의 트랜잭션 이력(Transaction History)에 해당 트랜잭션이 보이나 UTXO가 새로이 생기지는 않습니다.

앞서 설명한 수수료 무료 네트워크에 이 기능을 조합해서 사용하면 데이터 트랜잭션을 무제한 만들 수도 있습니다. 최소 하나의 UTXO는 필요하므로 초기에 필요한 만큼 충전을 해줘야 합니다. 단, 이 기능은 쓰면 한 트랜잭션에 Null Data가 2개 이상 존재하는 비 표준 트랜잭션을 생성합니다. 따라서 이 기능은 비 표준 트랜잭션을 허용하는 프라이빗 네트워크에만 사용 가능합니다.

TransactionBuilder의 addDataAddr(String dataAddress) 함수를 이용하면 직접 사용자 지정 Address-Data를 추가할 수 있습니다. 함수 명에서 알 수 있듯이 addOutput처럼 여러개의 주소를 할당할 수 있습니다.

TransactionBuilder txBuilder = new TransactionBuilder();
// tx output의 순서를 맞추기 위해 shuffleOutput을 끄는게 좋습니다.
txBuilder.shuffleOutputs(false);
// 첫번째 대상 주소를 추가합니다.
txBuilder.addDataAddr(TARGET_ADDR_1);
// 두번째 대상 주소를 추가합니다.
txBuilder.addDataAddr(TARGET_ADDR_2);
txBuilder.

그 외에 코인스택에서 제공하는 Openkeychain, 스마트 컨트랙트, TransactionSender 등에서 Address-Data를 사용하도록 하려면 다음과 같이 CoinStackClient을 설정해 야 합니다.

coinstackClient.initUseAddrData(true);

위와 같이 CoinStackClient를 설정하면 이후 이를 사용해 생성하는 코인스택이 제공하는 프로토콜(Openkeychain 등)의 트랜잭션들은 데이터 대상을 지정할때 dusty 아웃풋 아닌 address-data를 기본으로 사용하게 됩니다.

3. Utxo Cache

비트코인 트랜잭션은 UTXO 기반으로, 트랜잭션을 생성하기 위해서는 사용하지 않은 다른 트랜잭션의 아웃풋을 입력으로 받아야 합니다. 코인스택에서는 사용자가 클라이언트에서 직접 UTXO를 관리하는 부담을 줄이기 위해 트랜잭션 빌더를 통해 트랜잭션을 생성하는 시점에 코인스택 서버로 부터 매번 사용 가능한 UTXO를 조회해 사용하도록 되어 있습니다. 그러나 이로 인해 트랜잭션 생성 시 추가적인 시간(Latency)이 필요하게 됩니다. 따라서 매번 서버로부터 UTXO를 가져오지 않고 UTXO를 SDK 레벨에서 캐싱해 두고 필요한 만큼 사용하게 하면 UTXO 조회 시간만큼 트랜잭션 생성 시간을 줄일 수 있습니다.

단, 캐시의 효과를 보려면 개인키를 여러 서비스나 쓰래드가 공유하지 않고 하나의 서비스가 하나의 개인키로 여러번의 트랜잭션을 지속적으로 전송하는 경우여야만 합니다. 만약에 여러 서비스나 쓰래드에서 동시에 하나의 개인키를 공유해서 쓸 경우 double spent가 발생하므로 절대 하나의 개인키를 여럿이 공유하지 않아야 합니다. 여러개의 서비스가 블록체인에 접근할 경우 서비스 마다 다른 개인키를 할당하여 사용하십시오.

캐시 기능을 사용하려면 SDK에서 CoinStackClient 객체를 다음과 같이 설정합니다.

coinstackClient.initUtxoCache(cacheSize);

여기에 입력하는 cacheSize 사용할 개인키의 개수만큼 (e.g. 서비스가 하나의 개인키만 쓴다면 1을, 2개의 개인키를 필요에 따라 번갈아 가며 사용한다면 2를) 입력하는 것을 추천합니다. 여기에 입력한 cacheSize 수 만큼의 개인키에 대한 UTXO(저장하는 UTXO는 개수 무제한) 최대 1분동안 유지합니다. 캐시는 처음 트랜잭션 빌드 시 채워지고 트랜잭션 전송시 업데이트 됩니다. 트랜잭션 전송 에러가 발생하거나 잔고가 부족하면 캐시를 삭제하고 서버로 부터 다시 UTXO를 가져옵니다.

Last updated